diff -ur --new-file old/linux/CREDITS new/linux/CREDITS --- old/linux/CREDITS Sat Jun 8 17:55:40 1996 +++ new/linux/CREDITS Mon Aug 12 12:33:48 1996 @@ -26,11 +26,13 @@ S: Switzerland N: H. Peter Anvin -E: Peter.Anvin@linux.org +E: hpa@zytor.com +W: http://www.zytor.com/~hpa/ +P: 2047/2A960705 BA 03 D3 2C 14 A8 A8 BD 1E DF FE 69 EE 35 BD 74 D: Author of the SYSLINUX boot loader, maintainer of the linux.* news -D: hierarchy, responsible for various console and other hacks +D: hierarchy and the Linux Device List; various kernel hacks S: 4390 Albany Dr. #46 -S: San Jose CA 95129 +S: San Jose, California 95129 S: USA N: Derek Atkins @@ -127,6 +129,15 @@ E: bir7@leland.Stanford.Edu D: Original author of the Linux networking code +N: Philip Blundell +E: pjb27@cam.ac.uk +E: pb@nexus.co.uk +E: phil@tazenda.demon.co.uk +D: Device driver hacking (especially EtherExpress16/3C505 net cards) +D: Some Linux/ARM stuff +S: Trinity College +S: Cambridge, UK. CB2 1TQ + N: Thomas Bogendoerfer E: tsbogend@bigbug.franken.de D: Lance32 driver @@ -199,7 +210,7 @@ E: chaffee@plateau.cs.berkeley.edu D: vfat filesystem S: 3674 Oakwood Terrace #201 -S: Fremont, CA 94536 +S: Fremont, California 94536 S: USA N: Chih-Jen Chang @@ -223,7 +234,8 @@ D: Originator of design for new combined interrupt handlers S: William Gates Department S: Stanford University -S: Stanford, California 94305, USA +S: Stanford, California 94305 +S: USA N: Juan Jose Ciarlante E: jjciarla@raiz.uncu.edu.ar @@ -454,7 +466,7 @@ D: Loopback speedup, qlogic scsi hacking, VT_LOCKSWITCH S: Department of Computer Science S: University of California, Riverside -S: Riverside, CA 92521-0304 +S: Riverside, California 92521-0304 S: USA N: Dmitry S. Gorodchanin @@ -478,7 +490,7 @@ E: jgotts@engin.umich.edu D: kernel hacker S: 8124 Constitution Apt. 7 -S: Sterling Heights, MI 48313 +S: Sterling Heights, Michigan 48313 S: USA N: Grant Guenther @@ -542,6 +554,13 @@ S: 34266 Niestetal S: Germany +N: Richard Henderson +E: rth@tamu.edu +D: Alpha/ELF, gcc, binutils, and glibc +S: 304 E. North Ave. +S: Bryan, Texas 77801-3431 +S: USA + N: Sebastian Hetze E: she@lunetix.de D: German Linux Documentation, @@ -565,6 +584,14 @@ S: Dulles, Virginia 20166 S: USA +N: Kenji Tsutomu Hollis +E: khollis@bitgate.com +W: http://www.nurk.org/ +D: Berkshire PC Watchdog Driver +S: PO Box 15 +S: Grants Pass, Oregon 97526 +S: USA + N: Nick Holloway E: Nick.Holloway@alfie.demon.co.uk E: Nick.Holloway@parallax.co.uk @@ -795,7 +822,7 @@ S: 00200 Helsinki S: Finland -N: Kai M"akisara +N: Kai Mäkisara E: Kai.Makisara@metla.fi D: SCSI Tape Driver @@ -854,11 +881,11 @@ N: Mike McLagan E: mike.mclagan@linux.org W: http://www.invlogic.com/~mmclagan +D: DLCI/FRAD drivers for Sangoma SDLAs S: Innovative Logic Corp S: P.O. Box 1068 S: Laurel, MD 20732 S: USA -D: DLCI/FRAD drivers for Sangoma SDLAs N: Bradley McLean E: brad@bradpc.gaylord.com @@ -886,11 +913,11 @@ N: Nigel Metheringham E: Nigel.Metheringham@ThePLAnet.net +P: 1024/31455639 B7 99 BD B8 00 17 BD 46 C1 15 B8 AB 87 BC 25 FA D: IP Masquerading work and minor fixes S: Planet Online S: The White House, Melbourne Street, LEEDS S: LS2 7PS, UK -P: 1024/31455639 B7 99 BD B8 00 17 BD 46 C1 15 B8 AB 87 BC 25 FA N: Craig Metz E: cmetz@tjhsst.edu @@ -1001,9 +1028,10 @@ N: David C. Niemi E: niemi@erols.com -D: Mtools/VFAT/floppy work, benchmarking, random kernel dilettante +D: Assistant maintainer of Mtools, fdutils, and floppy driver +D: Administrator of WAUUG Linux Server, http://linux.wauug.org S: 2364 Old Trail Drive -S: Reston, Virginia 22091 +S: Reston, Virginia 20191 S: USA N: Michael O'Reilly @@ -1029,6 +1057,13 @@ S: Thunder Bay, Ontario S: CANADA P7C 5M9 +N: Yuri Per +E: yuri@pts.mipt.ru +D: Some smbfs fixes +S: Demonstratsii 8-382 +S: Tula 300000 +S: Russia + N: Kai Petzke E: wpp@marie.physik.tu-berlin.de W: http://physik.tu-berlin.de/~wpp @@ -1054,23 +1089,27 @@ D: The Linux Support Team Erlangen N: Daniel Quinlan -E: quinlan@yggdrasil.com -D: FSSTND Coordinator -S: 816 Saratoga Avenue, Apartment M208 -S: San Jose, California 95129 +E: Daniel.Quinlan@linux.org +W: http://www.bucknell.edu/~quinlan +D: FSSTND coordinator; FHS editor +D: random Linux documentation, patches, and hacks +S: Box C-5083 +S: Bucknell University +S: Lewisburg, Pennsylvania 17837 S: USA N: Eric S. Raymond E: esr@thyrsus.com W: http://www.ccil.org/~esr/home.html -S: 22 South Warren Avenue -S: Malvern, PA 19355 USA D: ncurses library co-maintainer D: terminfo master file maintainer D: Distributions HOWTO editor D: Instigator, FHS standard D: Keeper of the Jargon File and curator of the Retrocomputing Museum D: Author, Emacs VC and GUD modes +S: 22 South Warren Avenue +S: Malvern, Pennsylvania 19355 +S: USA N: Stefan Reinauer E: stepan@home.culture.mipt.ru @@ -1085,7 +1124,7 @@ W: http://www.cfw.com/~roadcapw D: Author of menu based configuration tool, Menuconfig. S: 1407 Broad Street -S: Waynesboro, Va 22980 +S: Waynesboro, Virginia 22980 S: USA N: Florian La Roche @@ -1163,7 +1202,7 @@ E: sinster@darkwater.com D: Whatever I notice needs doing (so far: itimers, /proc) S: POB 64132 -S: Sunnyvale, CA 94088-4132 +S: Sunnyvale, California 94088-4132 S: USA N: Simon Shapiro @@ -1175,12 +1214,22 @@ S: Beaverton, OR 97008 S: USA +N: Mike Shaver +E: shaver@ingenia.com +W: http://neon.ingenia.com/~shaver/ +D: Network hacking, /proc/sys/net +S: c/o Ingenia Communications Corporation +S: Suite 4200, CTTC Building +S: 1125 Colonel By Drive +S: Ottawa, Ontario +S: Canada K1S 5R1 + N: John Shifflett E: john@geolog.com E: jshiffle@netcom.com D: Always IN2000 SCSI driver D: wd33c93 SCSI driver (linux-m68k) -S: San Jose, CA +S: San Jose, California S: USA N: Rick Sladkey @@ -1225,8 +1274,8 @@ N: Leo Spiekman E: spiekman@et.tudelft.nl -D: Optics Storage 8000AT cdrom driver W: http://dutettk.et.tudelft.nl/~spiekman +D: Optics Storage 8000AT cdrom driver S: Utrecht S: The Netherlands @@ -1241,13 +1290,13 @@ S: Denmark N: Drew Sullivan -W: http://www.ss.org/ E: drew@ss.org +W: http://www.ss.org/ +P: 1024/ACFFA969 5A 9C 42 AB E4 24 82 31 99 56 00 BF D3 2B 25 46 D: iBCS2 developer S: 22 Irvington Cres. S: Willowdale, Ontario S: Canada M2N 2Z1 -P: 1024/ACFFA969 5A 9C 42 AB E4 24 82 31 99 56 00 BF D3 2B 25 46 N: Tommy Thorn E: Tommy.Thorn@irisa.fr @@ -1257,7 +1306,7 @@ S: IRISA S: Universit=E9 de Rennes I S: F-35042 Rennes Cedex -S: FRANCE +S: France N: Jon Tombs E: jon@gtex02.us.es @@ -1324,7 +1373,7 @@ S: Taipei S: Taiwan 112, Republic of China S: 24335 Delta Drive -S: Diamond Bar, CA 91765 +S: Diamond Bar, California 91765 S: USA N: Simmule Turner @@ -1411,7 +1460,7 @@ S: Cornell University Computer Science Department S: Robotics and Vision Laboratory S: 4130 Upson Hall -S: Ithaca NY 14850 +S: Ithaca, New York 14850 S: USA N: Greg Wettstein @@ -1425,10 +1474,11 @@ S: Oncology Research Division Computing Facility S: Roger Maris Cancer Center S: 820 4th St. N. -S: Fargo, ND 58122 +S: Fargo, North Dakota 58122 +S: USA N: Hans-Joachim Widmaier -E: jbhr@sofal.tynet.sub.org +E: hjw@zvw.de D: AFFS rewrite S: Eichenweg 16 S: 73650 Winterbach @@ -1517,6 +1567,15 @@ S: San Jose, California 95148 S: USA -# Don't add your name here, unless you really _are_ after Leonard -# alphabetically. Leonard is very proud of being the last entry, -# and this file really _is_ supposed to be in alphabetic order. +N: Marc Zyngier +E: maz@gloups.fdn.fr +D: MD driver +S: 11 rue Victor HUGO +S: 95560 Montsoult +S: France + +# Don't add your name here, unless you really _are_ after Marc +# alphabetically. Leonard used to be very proud of being the +# last entry, and he'll get positively pissed if he can't even +# be second-to-last. (and this file really _is_ supposed to be +# in alphabetic order) diff -ur --new-file old/linux/Documentation/Changes new/linux/Documentation/Changes --- old/linux/Documentation/Changes Thu Jun 6 16:44:17 1996 +++ new/linux/Documentation/Changes Mon Aug 19 08:45:51 1996 @@ -3,7 +3,7 @@ This document contains a list of the latest releases of the most important packages for Linux as well as instructions for newcomers to -the 1.3.x series of kernels. By glancing through it, you should be +the 2.0.x series of kernels. By glancing through it, you should be able to find out what you need to upgrade in order to successfully run the latest kernels. @@ -18,24 +18,42 @@ Taylor. Check out http://www.cviog.uga.edu/LinuxBleed.html if you prefer a HTML-ized shopping list. -Last updated: June 6, 1996. + Para aquellos que prefieran una version en castellano de este +documento, consultad la traduccion de Alfredo Sanjuan en +http://slug.ctv.es/~alfredo/Cambios.html. + + Akik magyarul szeretnenek olvasni az uj kernellel kapcsolatos +valtozasokrol, az alabbi cimen megtalaljak Nyitrai Tamas forditasat: +http://www.datanet.hu/generations/linux/newkernel.html. + + Tamas also maintains a version of this file in English at +http://www.datanet.hu/generations/linux/Changes.html. + + For people who prefer Japanese (thanks to Mitsuhiro Kojima): Kono +bunshou no nihongo ban wa +http://jf.gee.kyoto-u.ac.jp/JF/v2.0/Changes-2.0.html ni arimasu. + +Last updated: August 18, 1996. Current Author: Chris Ricker (gt1355b@prism.gatech.edu). Current Releases **************** -- Kernel modules Stable: 1.3.57, Exp: 1.3.69k -- PPP daemon Stable: 2.2.0f +- Kernel modules 2.0.0 +- PPP daemon 2.2.0f - Dynamic linker (ld.so) 1.7.14 - GNU CC 2.7.2 - Binutils 2.6.0.14 - Linux C Library Stable: 5.2.18, Beta: 5.3.12 - Linux C++ Library 2.7.1.4 - Termcap 2.0.8 -- Procps 0.99a -- Gpm 1.09 -- SysVinit 2.62 +- Procps 1.01 +- Gpm 1.10 +- SysVinit 2.64 - Util-linux 2.5 +- Mount 2.5k +- Net-tools 1.32-alpha +- Kbd 0.91 Upgrade notes ************* @@ -58,18 +76,24 @@ Booting Changes =============== - The boot stuff in 1.3.x (for arch/i386) has been enhanced so that it -now can load bigger kernels (bzImage) and that the loaders now can load -an initial ramdisk (initrd). For initrd see Documentation/initrd.txt. -For building bigger kernels use one of the following make targets: -bzImage, bzlilo, bzdisk (equivalent to make targets zImage, zlilo, and -zdisk respectively). If you want or need to use the new features -you'll need to upgrade your bootloaders. Lilo can be found at -ftp://lrcftp.epfl.ch/pub/linux/local/lilo/lilo.19.tar.gz. LOADLIN is at + The boot support in 2.0.x (for arch/i386) has been enhanced so that +it now can load bigger kernels (bzImage) and that the loaders now can +load an initial ramdisk (initrd). For initrd see +Documentation/initrd.txt. For building bigger kernels use one of the +following make targets: bzImage, bzlilo, bzdisk (equivalent to make +targets zImage, zlilo, and zdisk respectively). If you want or need to +use the new features you'll need to upgrade your bootloaders. Lilo can +be found at ftp://lrcftp.epfl.ch/pub/linux/local/lilo/lilo.19.tar.gz. +LOADLIN is at ftp://sunsite.unc.edu/pub/Linux/system/Linux-boot/lodlin16.tgz. If you're using more unusual loaders like SysLinux or etherboot, the latest versions are 1.3 and 2.0, respectively. + Ramdisk support does not work with the latest kernels if ramdisk=0 +option is present. Many older distributions (mainly Slackware) have +this option in their lilo.config file. Comment it out and re-run lilo +if you need ramdisks. + The Linux C Library =================== @@ -82,7 +106,7 @@ release there are some important changes that may cause troubles to buggy programs (programs that call free() on a pointer not returned by malloc() work with previous libc, but not with this release) so read the -`release.libc-5.3.9' file carefully! In the latest libc releases a +`release.libc-5.3.12' file carefully! In the latest libc releases a dirent bug, which erroneously defined d->reclen to d->namlen if USE_GNU was defined, has been fixed. Unfortunately, some GNU packages depend on this bug. GNU make 3.xx is one of them. To fix that you need to @@ -98,10 +122,10 @@ `fcntl_setlk() called by process 123 with broken flock() emulation' - then you need to upgrade to libc-5.2.18 as well. A proper (in other -words, BSD-style ;-) flock system call was added in 1.3.x, and older -libc's will now give this error. It doesn't *really* matter, so you -can just ignore it. If it really annoys you, upgrade libc (and + then you need to upgrade to at least libc-5.2.18 as well. A proper +(in other words, BSD-style ;-) flock system call was added to 2.0.x, +and older libc's will now give this error. It doesn't *really* matter, +so you can just ignore it. If it really annoys you, upgrade libc (and recompile any static binaries you might have that are linked against the old libc). If you're feeling lazy, just comment out @@ -111,44 +135,52 @@ in linux/fs/locks.c and recompile. If you're still running a.out, there's an unofficial libc-4.7.6 release out to which you can upgrade -to fix this problem. +to fix this problem. Libc is available from +ftp://sunsite.unc.edu/pub/Linux/GCC/. -The Termcap Library +GCC Signal 11 error =================== - The current Termcap release is 2.0.8. If you upgrade to this release -read the `README' file contained into the package to get some important -information about the `tgetent' function changes! + Many people have been reporting messages like the following, +especially when compiling a new kernel: + + `gcc: Internal compiler error: program cc1 got fatal signal 11'. + + This is NOT a kernel bug. Rather, these messages are generally +caused by hardware problems. See http://www.bitwizard.nl/sig11/ for +the sig11 FAQ. + + On the other hand, if you're using a gcc patched for Pentium +optimization and are getting these errors, downgrade to a standard GNU +gcc before assuming your hardware (or the kernel) is to blame.. + + On a related note, if you get random OOPses that don't seem to be +related to anything and you have a motherboard with APM support, try +disabling the APM support and/or compiling the kernel with APM support. Procps utilities ================ - In the latest 1.3.x kernel releases the /proc file system structure -was changed, so you need to upgrade the procps package to version -0.99a. In the very latest kernels, /proc has changed again. There's -not yet an officially updated version of procps, so use 0.99a; you -might want to look for one of the patches floating around to update -0.99a for use with 1.3.94 and later kernels. + Due to changes in the structure of the /proc filesystem, you need to +upgrade procps to the latest release, currently 1.01. Otherwise, +you'll get floating point errors with some ps commands or other similar +surprises. Grab +ftp://sunsite.unc.edu/pub/Linux/system/Status/ps/procps-1.01.tgz. Kernel Modules ============== - 1.3.x is almost completely modularized, and kerneld is now + Almost all drivers in 2.0.x can be modules, and kerneld is now incorporated into the kernel. To take advantage of this, you'll need -the latest version of the module support apps. The latest non-beta is -modules-1.3.57.tar.gz, and the latest beta is modules-1.3.69k.tar.gz. -These should be available at the same place you picked up your kernel -(ftp://ftp.funet.fi/pub/Linux/kernel/src/) and the home page is -http://www.pi.se/blox/modules/index.html. Note: If you try to load a -module and get a message like +the latest version of the module support apps. These are available at +http://www.pi.se/blox/modules/modules-2.0.0.tar.gz. Note: If you try to +load a module and get a message like `gcc2_compiled, undefined Failed to load module! The symbols from kernel 1.3.foo don't match 1.3.foo' - where `foo' is a number for a recent kernel, then it's time to -upgrade module utilities from 1.3.57 to the latest beta 1.3.69; you'll -only get this error if you're running the latest binutils, so most -people don't need to upgrade past 1.3.57. + where `foo' is a number for a recent kernel, then it's definitely +time to upgrade module utilities. Another little tip: you can't have both a.out *and* ELF support compiled as modules. Otherwise, you get a nice Catch-22 when you try @@ -160,7 +192,7 @@ have to mount at startup have to have their necessary file system and device drivers compiled into the kernel, so don't get grandiose ideas about going completely modular and then forget to compile ext2fs -support and ide drive support into your kernel ;-). +support and ide/SCSI drive support into your kernel ;-). PPP driver ========== @@ -179,11 +211,12 @@ your computer shuts down fine but "INIT: error reading initrequest" or words to that effect scroll across your screen hundreds of times. To fix, upgrade to -ftp://ftp.cistron.nl/pub/people/miquels/debian/sysvinit-2.62.tar.gz. +ftp://sunsite.unc.edu/pub/Linux/system/Daemons/init/sysvinit-2.64.tar.gz. - If you're trying to run NCSA httpd, you have to set pre-spawning of -daemons to zero, as it incorrectly assumes SunOS behavior. I recommend -you just switch to Apache httpd. + If you're trying to run NCSA httpd, you might have problems with +pre-spawning daemons. Upgrade to the latest release (1.5.2), available +from http://hoohoo.ncsa.uiuc.edu/ or check out Apache +(http://www.apache.org/). The new named pipe behavior also causes problems with Hylafax. If you're running the hylafax daemon, it will just keep eating up CPU time @@ -216,7 +249,7 @@ Older uugettys will not allow use of a bidirectional serial line. To fix this problem, upgrade to -ftp://sunsite.unc.edu/pub/Linux/system/Serial/getty_ps-2.0.7h.tar.gz. +ftp://sunsite.unc.edu/pub/Linux/system/Serial/getty_ps-2.0.7i.tar.gz. Kbd === @@ -224,6 +257,15 @@ For those of you needing non-ASCII character/font support, you should upgrade to ftp.funet.fi:/pub/OS/Linux/PEOPLE/Linus/kbd-0.91.tar.gz. +Mount +===== + + The mount util is distributed as part of util-linux, which is +currently at release 2.5. Some may find, especially when using the +loop or xiafs file system, NFS, or automounting, that they need to +upgrade to the latest release of mount, available from +ftp://ftp.win.tue.nl/pub/linux/util/mount-2.5k.tar.gz. + Console ======= @@ -237,7 +279,14 @@ ln -s /usr/lib/terminfo/l/linux /usr/lib/terminfo/c/console Better yet, just get the latest official Linux termcap from -ftp://sunsite.unc.edu/pub/Linux/GCC/termcap-2.0.8.tar.gz +ftp://sunsite.unc.edu/pub/Linux/GCC/termcap-2.0.8.tar.gz. If you +upgrade to this release read the `README' file contained into the +package to get some important information about the `tgetent' function +changes! Note that there is now a fixed version at +ftp://sunsite.unc.edu/pub/Linux/GCC/termcap-2.0.8.fix. If some of your +apps complain that termcap entries are too long and you don't need some +of the more esoteric terms in the standard 2.0.8 termcap, just download +termcap-2.0.8.fix and move it to /etc/termcap. Also, the console driver is now responsible for keeping track of correspondence between character codes and glyph bitmaps. If you @@ -249,7 +298,7 @@ Hdparm has been upgraded to take advantage of the latest features of the kernel drivers. The latest non-beta version can be found at -ftp://sunsite.unc.edu/pub/Linux/kernel/patches/diskdrives/hdparm-2.7.tar.gz. +ftp://sunsite.unc.edu/pub/Linux/kernel/patches/diskdrives/hdparm-3.1.tar.gz. IP Accounting ============= @@ -263,20 +312,20 @@ There also exists a possibility to match on device names and/or device addresses, so that only packets coming in/going out via that device (network interface) match with a rule. You'll need to get -ipfwadm from ftp://ftp.xos.nl/pub/linux/ipfwadm/ipfwadm-2.1.tar.gz to +ipfwadm from ftp://ftp.xos.nl/pub/linux/ipfwadm/ipfwadm-2.3.0.tar.gz to use this. IP Firewalls ============ - The IP firewall code has been changed drastically during 1.3.x. -There are now 3 categories of firewall rules: one for incoming packets, -one for outgoing packets, and one for packets being forwarded. There -also exists a possibility to match on device names and/or device -addresses, so that only packets coming in/going out via that device -(network interface) match with a rule. This is especially useful to -prevent spoofing. You'll need to get -ftp://ftp.xos.nl/pub/linux/ipfwadm/ipfwadm-2.1.tar.gz to use this. + The IP firewall code has been changed drastically for 2.0.x. There +are now 3 categories of firewall rules: one for incoming packets, one +for outgoing packets, and one for packets being forwarded. There also +exists a possibility to match on device names and/or device addresses, +so that only packets coming in/going out via that device (network +interface) match with a rule. This is especially useful to prevent +spoofing. You'll need to get +ftp://ftp.xos.nl/pub/linux/ipfwadm/ipfwadm-2.3.0.tar.gz to use this. IP Masquerading =============== @@ -285,32 +334,36 @@ always need to load separate modules (ip_masq_ftp.o and/or ip_masq_irc.o) if you are going to use FTP or IRC in combination with masquerading. You'll need to get -ftp://ftp.xos.nl/pub/linux/ipfwadm/ipfwadm-2.1.tar.gz to use this. +ftp://ftp.xos.nl/pub/linux/ipfwadm/ipfwadm-2.3.0.tar.gz to use this. ISDN support ============ The new kernels support ISDN. You'll need ISDN utils available from -ftp://ftp.franken.de/pub/isdn4linux/isdn4k-utils-1.3.97.tar.gz to try +ftp://ftp.franken.de/pub/isdn4linux/v2.0/isdn4k-utils-2.0.tar.gz to try this. -Term is broken -============== +Frame Relay +=========== - Term (a comm line multiplexer similar in purpose to slirp) does not -work with kernels later than 1.3.60. Since the author of term is -apparently currently on vacation, there is no fix forthcoming. I -suggest that those of you who rely on term learn to use slirp. + Frame relay support for Linux is now available as well. Currently, +only Sangoma cards are supported, but the interface is such that others +will be as drivers become available. To use this, grab +ftp://ftp.invlogic.com/linux/frad-0.15.tgz and +ftp://ftp.invlogic.com/linux/routing.tgz. Networking ========== Some of the /proc/net entries have changed. You'll need to upgrade to the latest net-tools in -ftp://ftp.inka.de:/pub/comp/Linux/networking/net-tools. The last -official release there is net-tools-1.2.0.tar.gz, and the latest -release is net-tools-1.32-alpha.tar.gz. If you need the upgrade, you -probably need the latest beta release. +ftp://ftp.inka.de/pub/comp/Linux/networking/NetTools/, where the latest +is currently net-tools-1.32-alpha.tar.gz. See +http://www.inka.de/sites/lina/linux/NetTools/index_en.html for more +information. Note that there is currently no ipfw (which is part of +net-tools) which works with 2.0.x kernels. If you need its functions, +learn how to use ipfwadm or patch ipfw to get it to work (ipfw's current +maintainer does not currently have time to fix it). Xntpd ===== @@ -322,7 +375,7 @@ Sound driver ============ - The sound driver was upgraded in the 1.3.x kernels, breaking vplay. + The sound driver was upgraded in the 2.0.x kernels, breaking vplay. To fix this problem, get a new version of the sndkit from ftp://ftp.best.com/pub/front/tasd/snd-util-3.5.tar.gz. Some users report that various other sound utils (cdd2wav-sbpcd, for example) need @@ -352,37 +405,36 @@ Loop device =========== - 1.3.x kernels include loop device support which lets you mount a + 2.0.x kernels include loop device support which lets you mount a file as a file system, which can allow for all sorts of cool things like encrypted file systems and such. To use it, you'll need a modified version of mount from -ftp://ftp.win.tue.nl/pub/linux/util/mount-2.5X.tar.gz and preliminary -work on encrypted file system support can be found in -ftp.funet.fi:/pub/OS/Linux/BETA/loop/des.1.tar.gz. +ftp://ftp.win.tue.nl/pub/linux/util/mount-2.5k.tar.gz; preliminary work +on encrypted file system support can be found in +ftp.funet.fi:/pub/Linux/BETA/loop/des.1.tar.gz. Multiple device =============== Multiple device support (allowing you to group several partitions into one logical device) has also been added. Check out -ftp://sweet-smoke.ufr-info-p7.ibp.fr/pub/Linux/md034.tar.gz to try this +ftp://sweet-smoke.ufr-info-p7.ibp.fr/pub/Linux/md035.tar.gz to try this out. Arp === Arp daemon support has been added. Check out -http://www.loran.com/~layes/arpd/index.html for more info and a copy of -arpd. +http://www.loran.com/~layes/arpd/index.html for more info and +http://www.loran.com/~layes/arpd/arpd-1.0.2.tar.gz for a copy of arpd. Quota ===== - Quota support has also been added. You need to get quotas-1.51 from -ftp://ftp.funet.fi/pub/Linux/PEOPLE/Linus/subsystems/quota/all.tar.gz. -This will compile just fine after you copy its mntent.h over to -/usr/include/mntent.h. I've uploaded this to sunsite as -ftp://sunsite.unc.edu/pub/Linux/system/Admin/quotas-1.51-tar.gz + Quota support has also been added. You need to get quotas-1.55 from +ftp://ftp.funet.fi/pub/Linux/kernel/src/subsystems/quota/all.tar.gz. You +may need to copy its mntent.h over to /usr/include/mntent.h to get it to +compile. Process Accounting ================== @@ -391,12 +443,18 @@ kernels. To use this feature, you'll need to get ftp://iguana.hut.fi/pub/linux/Kernel/process_accounting/acct_1.3.73.tar.gz. -Bdflush -======= +Bdflush and Updated +=================== Bdflush has also been integrated into the new kernels, so those of you using it on older systems no longer need to hunt for the patches to -implement it once you upgrade to 1.3.x. +implement it once you upgrade to 2.0.x. You do still need to run the +update daemon, however. You should probably upgrade to the latest +updated, currently +ftp://sunsite.unc.edu/pub/Linux/system/Daemons/updated-1.2.tar.gz. This +(and later) versions will not spawn a bdflush daemon, since that is now +done by the kernel (kflushd). If you upgrade, be sure to leave update +in your init scripts and remove bdflush. APM support =========== @@ -410,19 +468,20 @@ iBCS and Dosemu =============== - For a version of iBCS that works with 1.3.x kernels, grab -ftp://tsx-11.mit.edu/pub/linux/BETA/ibcs2/ibcs-1.3-960404-ALPHA.tar.gz + For a version of iBCS that works with 2.0.x kernels, grab +ftp://tsx-11.mit.edu/pub/linux/BETA/ibcs2/ibcs-2.0-960610.tar.gz For a version of Dosemu that works (well, at least as well as DOS ever works ;-), get -ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/Development/dosemu-0.63.1.19.tgz. -Be sure to follow the instructions in README.newkernels about patching -your include files, or it will not compile. +ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/Development/dosemu-0.63.1.55.tgz +or check out http://www.ednet.ns.ca/auto/rddc. Be sure to follow the +instructions in README.newkernels about patching your include files, or +it will not compile. Mtools and Fdutils ================== - The floppy ioctl numbering scheme has changed in 1.3.x. For + The floppy ioctl numbering scheme has changed for 2.0.x. For backwards compatibility, the old system was supported through 1.3.x and will generate a warning in 2.0. In 2.1.x, the old scheme will disappear entirely. @@ -437,6 +496,59 @@ In the future, fdformat might disappear entirely, so get used to using superformat instead. +Cyclades Serial Driver +====================== + + The Cyclades driver has been changed so that the minor numbers start +at 0 instead of 32 (for example, ttyC0 should be major 19, minor 0 for +2.0.x kernels; in older kernels, it would have been major 19, minor +32). Use mknod or a sufficiently new version of MAKEDEV to fix this. + +NCR 53c810 SCSI Driver +====================== + + Drivers for this card are now included in the standard linux source. +However, they require Perl to be installed before they will compile. +As far as I know, this is the only code in the kernel source that +requires Perl to compile. If your kernel compile fails and you happen +to have included this driver in your configuration, make sure you have +Perl installed. + +Perl +==== + + While we're on the subject, changes made for the 2.0.x series cause +the connect() Perl (both 4 and 5) call to time out while connecting to +remote systems. The problem is not actually in the connect() call; +rather, the optional bind() call usually used with connect() causes the +problem. Remove the bind() call and your Perl scripts should connect. + + Also, Perl scripts using the readdir call now misbehave if you're +using an old version of Perl, due to changes in libc. Upgrade to a +more current Perl to avoid any unpleasantness. + +Groff +===== + + Those of you running Slackware may experience weirdness with man +pages due to changes in groff. If your man pages display for - +when present at the end of a line, try setting an appropriate value +(many have reported success with "latin1", for example) for the +environmental variable LESSCHARSET. Another, and probably better, +solution is to edit the file /usr/lib/man.config and change all +`-Tlatin1' options to `-Tascii'. An alternate solution, for those of +you who can't reformat your man files in .../cat* directories is to +edit /usr/lib/man.config, setting the PAGER to `PAGER +(LESSCHARSET=latin1;export LESSCHARSET;/usr/bin/less -is)'. + +E2fsprogs +========= + + e2fsprogs 1.02 will work with the latest kernels, but it cannot be +compiled on them. If you need (or want) to compile your own copy, +you'll need to get the latest version, currently available at +ftp://tsx-11.mit.edu/pub/linux/packages/ext2fs/e2fsprogs-1.04.tar.gz. + How to know the version of the installed programs ************************************************* @@ -492,8 +604,11 @@ ================= ftp://sunsite.unc.edu/pub/Linux/GCC/libg++-2.7.1.4.bin.tar.gz +ftp://sunsite.unc.edu/pub/Linux/GCC/libg++-2.7.1.3.bin.tar.gz Installation notes: ftp://sunsite.unc.edu/pub/Linux/GCC/release.libg++-2.7.1.4 +ftp://sunsite.unc.edu/pub/Linux/GCC/release.libg++-2.7.1.3 +Use 2.7.13 with libc 5.2.18 and 2.7.14 with libc 5.3.12. Dynamic Linker ============== @@ -509,9 +624,7 @@ ================= The latest public release: -ftp://sunsite.unc.edu/pub/Linux/kernel/modules-1.3.57.tar.gz -The latest experimental release: -http://www.pi.se/blox/ +ftp://sunsite.unc.edu/pub/Linux/kernel/modules-2.0.0.tar.gz PPP Daemon and utilities ======================== @@ -522,18 +635,18 @@ Procps utilities ================ -ftp://sunsite.unc.edu/pub/Linux/system/Status/ps/procps-0.99a.tgz +ftp://sunsite.unc.edu/pub/Linux/system/Status/ps/procps-1.01.tgz Gpm mouse utilities =================== -ftp://iride.unipv.it/pub/gpm/gpm-1.09.tar.gz -ftp://sunsite.unc.edu/pub/Linux/system/Daemons/gpm-1.09.tar.gz +ftp://iride.unipv.it/pub/gpm/gpm-1.10.tar.gz +ftp://sunsite.unc.edu/pub/Linux/system/Daemons/gpm-1.10.tar.gz SysVinit utilities ================== -ftp://sunsite.unc.edu/pub/Linux/system/Daemons/init/sysvinit-2.62.tar.gz +ftp://sunsite.unc.edu/pub/Linux/system/Daemons/init/sysvinit-2.64.tar.gz Util-linux ========== @@ -561,10 +674,18 @@ distribution), most of these are available in RPM format. Check around 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. +upgrade to install. Almost everything you need is available in +ftp://ftp.redhat.com/pub/current/i386/updates/2.0-kernel/ and its +mirrors. + + For others, especially those of you running Slackware 3.0, David +Bourgin has put together a Slackware-compatible package of everything +necessary to quickly and easily upgrade to 2.0.x. See +ftp://ftp.wsc.com/pub/freeware/linux/update.linux/ for more information +and the files. -Please send info about any other packages that 1.3.x "broke" or about -any new features of 1.3.x that require extra or new packages for use to +Please send info about any other packages that 2.0.x "broke" or about +any new features of 2.0.x that require extra or new packages for use to Chris Ricker (gt1355b@prism.gatech.edu). I generate this from a modified texinfo setup, so you don't need to bother generating a diff against the current version before you send the additional information diff -ur --new-file old/linux/Documentation/Configure.help new/linux/Documentation/Configure.help --- old/linux/Documentation/Configure.help Thu Aug 29 16:32:43 1996 +++ new/linux/Documentation/Configure.help Thu Aug 29 16:33:30 1996 @@ -202,10 +202,9 @@ "SiS" chipset. Unfortunately, it has a number of rather nasty design flaws that can cause severe data corruption under many common conditions. Say Y here to include code which tries to automatically - detect and correct the problems under Linux. This also provides - support for the enhanced features of the CMD640, for improved - support/operation under linux, including access to the secondary IDE - ports in some systems. This driver will work automatically in PCI + detect and correct the problems under Linux. + This option also enables access to the secondary IDE ports in some + CMD640 based systems. This driver will work automatically in PCI based systems (most new systems have PCI slots). But if your system uses VESA local bus (VLB) instead of PCI, you must also supply a kernel boot parameter to enable the CMD640 bugfix/support: @@ -213,6 +212,13 @@ Acculogic, and on the "CSA-6400E PCI to IDE controller" that some people have. If unsure, say Y. +CMD640 enhanced support +CONFIG_BLK_DEV_CMD640_ENHANCED + This option includes support for setting/autotuning PIO modes + and prefetch on CMD640 IDE interfaces. If you have a CMD640 IDE + interface and your BIOS does not already do this for you, then say Y + here. Otherwise say N. + RZ1000 chipset bugfix/support CONFIG_BLK_DEV_RZ1000 The PC-Technologies RZ1000 chip is used on many common 486 and @@ -238,34 +244,35 @@ This driver is enabled at runtime using the "ide0=dtc2278" kernel boot parameter. It enables support for the secondary IDE interface of the DTC-2278 card, and permits faster I/O speeds to be set as - well. See the README.ide and dtc2278.c files for more info. + well. See the Documentation/ide.txt and dtc2278.c files for more + info. Holtek HT6560B support CONFIG_BLK_DEV_HT6560B This driver is enabled at runtime using the "ide0=ht6560b" kernel boot parameter. It enables support for the secondary IDE interface of the Holtek card, and permits faster I/O speeds to be set as well. - See the README.ide and ht6560b.c files for more info. + See the Documentation/ide.txt and ht6560b.c files for more info. QDI QD6580 support CONFIG_BLK_DEV_QD6580 This driver is enabled at runtime using the "ide0=qd6580" kernel - boot parameter. It permits faster I/O speeds to be set. - See the README.ide and qd6580.c files for more info. + boot parameter. It permits faster I/O speeds to be set. See the + Documentation/ide.txt and qd6580.c files for more info. UMC 8672 support CONFIG_BLK_DEV_UMC8672 This driver is enabled at runtime using the "ide0=umc8672" kernel boot parameter. It enables support for the secondary IDE interface of the UMC-8672, and permits faster I/O speeds to be set as well. - See the README.ide and umc8672.c files for more info. + See the Documentation/ide.txt and umc8672.c files for more info. ALI M1439/M1445 support CONFIG_BLK_DEV_ALI14XX This driver is enabled at runtime using the "ide0=ali14xx" kernel boot parameter. It enables support for the secondary IDE interface of the chipset, and permits faster I/O speeds to be set as well. - See the README.ide and ali14xx.c files for more info. + See the Documentation/ide.txt and ali14xx.c files for more info. PROMISE DC4030 support (EXPERIMENTAL) CONFIG_BLK_DEV_PROMISE @@ -273,9 +280,9 @@ boot parameter. It enables support for the secondary IDE interface of the chipset, and takes advantage of the caching features of the card. This driver is known to incur timeouts/retries during heavy - I/O to drives attached to the secondary interface. CDROM and - TAPE devices are not supported yet. - See the README.ide and promise.c files for more info. + I/O to drives attached to the secondary interface. CDROM and TAPE + devices are not supported yet. See the Documentation/ide.txt and + promise.c files for more info. XT harddisk support CONFIG_BLK_DEV_XD @@ -823,17 +830,19 @@ about 2kB. You may need to read the FIREWALL-HOWTO, available via ftp (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO. Also, you will need the - ipfwadm tool to allow selective blocking of internet traffic based + ipfwadm tool (available via ftp (user: anonymous) from ftp.xos.nl) + to allow selective blocking of internet traffic based on type, origin and destination. You need to enable IP firewalling in order to be able to use IP masquerading (i.e. local computers can chat with an outside host, but that outside host is made to think that it is talking to the firewall box. Makes the local network completely invisible and avoids the need to allocate valid IP host - addresses for the machines on the local net) or to use the ip packet + addresses for the machines on the local net) or to use the IP packet accounting to see what is using all your network bandwidth. This option is also needed when you want to enable the transparent - proxying support (via which non-local connections can be redirected - to local proxy servers). + proxying support (makes the computers on the local network think + they're talking to a remote computer, while in reality the traffic + is redirected by your Linux firewall to a local proxy server). IP: accounting CONFIG_IP_ACCT @@ -853,10 +862,12 @@ encapsulating protocol. This particular tunneling driver implements encapsulation of IP within IP, which sounds kind of pointless, but can be useful if you want to make your (or some other) machine - appear on a different network than it physically is, or to use the - mobile IP facilities (which effectively are doing that). Enabling this - option will produce two modules ( = code which can be inserted in - and removed from the running kernel whenever you want), one + appear on a different network than it physically is, or to use + mobile-IP facilities (allowing laptops to seamlessly move between + networks without changing their IP addresses; check out + http://anchor.cs.binghamton.edu/~mobileip/LJ/index.html). Enabling + this option will produce two modules ( = code which can be inserted + in and removed from the running kernel whenever you want), one encapsulator and one decapsulator. You can read details in drivers/net/README.tunnel. Most people can say N. @@ -868,10 +879,14 @@ IP: transparent proxying (EXPERIMENTAL) CONFIG_IP_TRANSPARENT_PROXY - This enables you to redirect any network traffic to a local server, - acting as a "transparent proxy server". Redirection is activated - by defining special input firewall rules (using the ipfwadm utility) - and/or by doing an appropriate bind() system call. + This enables your Linux firewall to transparently redirect any + network traffic originating from the local network and destined + for a remote host to a local server, called a "transparent proxy + server". This makes the local computers think they are talking to + the remote end, while in fact they are connected to the local + proxy. Redirection is activated by defining special input firewall + rules (using the ipfwadm utility) and/or by doing an appropriate + bind() system call. IP: masquerading (EXPERIMENTAL) CONFIG_IP_MASQUERADE @@ -889,28 +904,31 @@ last problem can also be solved by connecting the Linux box to the Internet using SLiRP [SLiRP is a SLIP/PPP emulator that works if you have a regular dial up shell account on some UNIX computer; get it - from ftp://sunsite.unc.edu/pub/Linux/system/Network/serial/ + from ftp://sunsite.unc.edu/pub/Linux/system/Network/serial/].) Details on how to set things up are contained in the IP Masquerading FAQ, available at http://www.indyramp.com/masq/ This is EXPERIMENTAL code, which means that it need not be completely stable. If you want this, say Y. -IP: always defragment -CONFIG_IP_ALWAYS_DEFRAG - This option means that all incoming fragments will be reassembled - (defragmented) before being processed, even if those packets - should be forwarded. This option is highly recommended if you - have enabled CONFIG_IP_MASQUERADE, because these facilities requires - that second and further fragments can be related to TCP or UDP port - numbers, which are only stored in the first fragment. When using - CONFIG_IP_FIREWALL, you might also want to enable this option, to - have a more reliable firewall (otherwise second and further fragments - will always be accepted by the firewall). When using transparent - proxying (CONFIG_IP_TRANSPARENT_PROXY), this option is implicit, - although it is safe to say Y here. Do not say Y to this option except - when running either a firewall that is the sole link to your network or - a transparent proxy. Never ever say Y to this for a normal router or - host. +IP: always defragment +CONFIG_IP_ALWAYS_DEFRAG + This option means that all incoming fragments (= parts of IP packets + that arose when some host between origin and destination decided + that the IP packets were too large and cut them in pieces) will be + reassembled (defragmented) before being processed, even if they are + about to be forwarded. This option is highly recommended if you + have enabled the masquerading support (CONFIG_IP_MASQUERADE), + because this facility requires that second and further fragments can + be related to TCP or UDP port numbers, which are only stored in the + first fragment. When using IP firewall support + (CONFIG_IP_FIREWALL), you might also want to enable this option, to + have a more reliable firewall (otherwise second and further + fragments will always be accepted by the firewall). When using + transparent proxying (CONFIG_IP_TRANSPARENT_PROXY), this option is + implicit, although it is safe to say Y here. Do not say Y to this + option except when running either a firewall that is the sole link + to your network or a transparent proxy. Never ever say Y to this for + a normal router or host. IP: aliasing support CONFIG_IP_ALIAS @@ -1347,13 +1365,14 @@ Adaptec AHA152X/2825 support CONFIG_SCSI_AHA152X - This is support for a SCSI host adaptor. It is explained in section - 3.3 of the SCSI-HOWTO, available via ftp (user: anonymous) at - sunsite.unc.edu:/pub/Linux/docs/HOWTO. If it doesn't work out of the - box, you may have to change some settings in drivers/scsi/aha152x.h. - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you - want). If you want to compile it as a module, say M here and read + This is support for the AHA-1510, AHA-1520, AHA-1522, and AHA-2825 + SCSI host adaptors. It is explained in section 3.3 of the + SCSI-HOWTO, available via ftp (user: anonymous) at + sunsite.unc.edu:/pub/Linux/docs/HOWTO. You might also want to read + the comments at the top of drivers/scsi/aha152x.c. This driver is + also available as a module ( = code which can be inserted in and + removed from the running kernel whenever you want). If you want to + compile it as a module, say M here and read Documentation/modules.txt. Adaptec AHA1542 support @@ -1417,26 +1436,27 @@ EATA-DMA (DPT, NEC, AT&T, SNI, AST, Olivetti, Alphatronix) support CONFIG_SCSI_EATA_DMA - This is support for the EATA-DMA protocol compliant SCSI Host Adaptors - like the SmartCache III/IV, SmartRAID controller families and the DPT - PM2011B and PM2012B controllers. - Please read the SCSI-HOWTO, available via ftp (user: anonymous) at - sunsite.unc.edu:/pub/Linux/docs/HOWTO. - This driver is also available as a module (= code which can be inserted - in and removed from the running kernel whenever you want). If you want - to compile it as a module, say M here and read Documentation/modules.txt. + This is support for the EATA-DMA protocol compliant SCSI Host + Adaptors like the SmartCache III/IV, SmartRAID controller families + and the DPT PM2011B and PM2012B controllers. Please read the + SCSI-HOWTO, available via ftp (user: anonymous) at + sunsite.unc.edu:/pub/Linux/docs/HOWTO. This driver is also + available as a module (= code which can be inserted in and removed + from the running kernel whenever you want). If you want to compile + it as a module, say M here and read Documentation/modules.txt. EATA-PIO (old DPT PM2001, PM2012A) support CONFIG_SCSI_EATA_PIO - This driver supports all EATA-PIO protocol compliant SCSI Host Adaptors - like the DPT PM2001 and the PM2012A. EATA-DMA compliant HBAs can also use - this driver but are discouraged from doing so, since this driver only - supports harddisks and lacks numerous features. - You might want to have a look at the SCSI-HOWTO, available via ftp - (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO. - If you want to compile this as a module ( = code which can be inserted - in and removed from the running kernel whenever you want), say M here - and read Documentation/modules.txt. + This driver supports all EATA-PIO protocol compliant SCSI Host + Adaptors like the DPT PM2001 and the PM2012A. EATA-DMA compliant + HBAs can also use this driver but are discouraged from doing so, + since this driver only supports harddisks and lacks numerous + features. You might want to have a look at the SCSI-HOWTO, + available via ftp (user: anonymous) at + sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you want to compile this + as a module ( = code which can be inserted in and removed from the + running kernel whenever you want), say M here and read + Documentation/modules.txt. UltraStor 14F/34F support CONFIG_SCSI_U14_34F @@ -1519,14 +1539,94 @@ allow DISCONNECT CONFIG_SCSI_NCR53C7xx_DISCONNECT - This enables the disconnect/reconnect feature of the NCR SCSI controller. - When this is enabled, a slow SCSI device will not lock the SCSI bus - while processing a request, allowing simultaneous use of e.g. a SCSI - hard disk and SCSI tape or CD-ROM drive, and providing much better - performance when using slow and fast SCSI devices at the same time. Some - devices, however, do not operate properly with this option enabled, and - will cause your SCSI system to hang, which might cause a system crash. - The safe answer therefore is to say N. + This enables the disconnect/reconnect feature of the NCR SCSI + controller. When this is enabled, a slow SCSI device will not lock + the SCSI bus while processing a request, allowing simultaneous use + of e.g. a SCSI hard disk and SCSI tape or CD-ROM drive, and + providing much better performance when using slow and fast SCSI + devices at the same time. Some devices, however, do not operate + properly with this option enabled, and will cause your SCSI system + to hang, which might cause a system crash. The safe answer + therefore is to say N. + +NCR53C8XX SCSI support +CONFIG_SCSI_NCR53C8XX + This is the BSD ncr driver adapted to linux for the NCR53C8XX family + of PCI-SCSI controllers. This driver supports parity checking, + tagged command queuing, fast scsi II transfer up to 10 MB/s with + narrow scsi devices and 20 MB/s with wide scsi devices. + This driver has been tested OK with linux/i386 and is currently + untested under linux/Alpha. If you intend to use this driver under + linux/Alpha, just try it first with read-only or mounted read-only + devices. Memory mapped io is currently not supported under + linux/Alpha. Please read drivers/scsi/README.ncr53c8xx for more + information. + +force normal IO +CONFIG_SCSI_NCR53C8XX_IOMAPPED + Under linux/Alpha only normal io is currently supported. + Under linux/i386, this option allows you to force the driver to use + normal IO. Memory mapped IO has less latency than normal IO. + During the initialization phase, the driver first tries to use + memory mapped io. If nothing seems wrong, it will use memory mapped + io. If a flaw is detected, it will use normal io. However, it's + possible that memory mapped does not work properly for you and the + driver has not detected the problem; then you would want to say Y + here. The normal answer therefore is N. + +not allow targets to disconnect +CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT + This option is only provided for safety if you suspect some scsi + device of yours to not support properly this feature. In that case, + you would say Y here. In general however, to not allow targets to + disconnect is not reasonable if there is more than 1 device on a + scsi bus. The normal answer therefore is N. + +enable tagged command queuing +CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE + This option allows you to enable tagged command queuing support at + linux start-up. Some scsi devices do not properly support this + feature. The suggested method is to say N here and to use the + "settags" control command after boot-up to enable this feature: + echo "settags 2 4" >/proc/scsi/ncr53c8xx/0 + asks the driver to use up to 4 concurrent tagged commands for target + 2 of controller 0. + See the file drivers/scsi/README.ncr53c8xx for more information. + WARNING! tagged queue support requires to allow targets to + disconnect (see above). + The safe answer therefore is N. + The normal answer therefore is Y. + +force asynchronous transfer mode +CONFIG_SCSI_NCR53C8XX_FORCE_ASYNCHRONOUS + This option allows you to force asynchronous transfer mode for all + devices at linux startup. You can enable synchronous negotiation + with the "setsync" control command after boot-up, for example: + echo "setsync 2 25" >/proc/scsi/ncr53c8xx/0 + asks the driver to set the period to 25 ns (10MB/sec) for target 2 + of controller 0 (please read drivers/scsi/README.ncr53c8xx for more + information). The safe answer therefore is Y. The normal answer + therefore is N. + +force synchronous negotiation +CONFIG_SCSI_NCR53C8XX_FORCE_SYNC_NEGO + Some scsi-2 devices support synchronous negotiations but do not + report this feature in byte 7 of inquiry data. + Answer Y only if you suspect some device to be so humble. + The normal answer therefore is N. + +disable master parity checking +CONFIG_SCSI_NCR53C8XX_DISABLE_MPARITY_CHECK + Some hardware may have problems with parity during master cycles on + PCI bus. Only seen once. Answer Y if you suspect such problem. The + normal answer therefore is N. + +disable scsi parity checking +CONFIG_SCSI_NCR53C8XX_DISABLE_PARITY_CHECK + Parity on scsi bus is a system option. If one device checks parity, + then all devices on the scsi bus must generate parity. However, the + parity can be ignored by the scsi devices. Answer Y only if you + know what you are doing. The normal answer therefore is N. Always IN2000 SCSI support CONFIG_SCSI_IN2000 @@ -1860,7 +1960,7 @@ interface. The driver supports the ser12 and par96 designs. To configure the driver, use the setbaycom utility available from http://www.ife.ee.ethz.ch/~sailer/ham/ham.html#lnxbay. For - informations on the modems, see http://www.baycom.de and + information on the modems, see http://www.baycom.de and drivers/char/README.baycom. If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read @@ -2655,7 +2755,7 @@ FX-001 or FX-001D CDROM drive. In addition, this driver uses much less kernel memory than the old one, if that is a concern. This driver is able to support more than one drive, but each drive needs a separate - interface card. + interface card. Check out Documentation/cdrom/mcdx. Matsushita/Panasonic/Creative, Longshine, TEAC CDROM support CONFIG_SBPCD @@ -2716,7 +2816,11 @@ Optics Storage DOLPHIN 8000AT CDROM support CONFIG_OPTCD - If this is your CDROM drive, say Y here. + This is the driver for the 'DOLPHIN' drive with a 34-pin Sony + compatible interface. It also works with the Lasermate CR328A. If + you have one of those, say Y. This driver does not work for the + Optics Storage 8001 drive; use the IDE-ATAPI CDROM driver for this + one. Sanyo CDR-H94A CDROM support CONFIG_SJCD @@ -3134,17 +3238,18 @@ serial ports. People who might say N here are those that are setting up dedicated ethernet WWW/ftp servers, or users that have one of the various bus mice instead of a serial mouse. (Note that - the Cyclades and Stallion drivers do not need this driver built in - for them to work. They are completely independent of each other.) - If you want to compile this driver as a module, say M here and read - Documentation/modules.txt. [WARNING: Do not compile this driver as - a module if you are using non-standard serial ports, since the - configuration information will be lost when kerneld automatically - unloads the driver. This limitation may be lifted in the future.] - Most people will say Y or M here, so that they can use serial mice, - modems and similar devices connecting to the standard serial ports. + the Cyclades and Stallion multi serial port drivers do not need this + driver built in for them to work. They are completely independent of + each other.) If you want to compile this driver as a module, say M + here and read Documentation/modules.txt. [WARNING: Do not compile + this driver as a module if you are using non-standard serial ports, + since the configuration information will be lost when kerneld + automatically unloads the driver. This limitation may be lifted in + the future.] Most people will say Y or M here, so that they can use + serial mice, modems and similar devices connecting to the standard + serial ports. -Digiboard PC/X Support +Digiboard PC/Xx Support CONFIG_DIGI This is a driver for the Digiboard PC/Xe, PC/Xi, and PC/Xeve cards that give you many serial ports. You would need something like this @@ -3225,6 +3330,22 @@ tells you how to specify the port and IRQ to be used by PLIP at module load time. + +Mouse Support (not serial mice) +CONFIG_MOUSE + This is for machines with a bus mouse or a PS/2 mouse as opposed to + a serial mouse. Most people have a regular serial MouseSystem or + Microsoft mouse (made by Logitech) that plugs into a COM port + (rectangular with 9 or 25 pins). These people say N here. If you + have something else, read the Busmouse-HOWTO, available via ftp + (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO and say Y + here. If you have a laptop, you either have to check the + documentation or experiment a bit to find out whether the trackball + is a serial mouse or not; it's best to say Y here for you. Note that + the answer to this question won't directly affect the kernel: saying + N will just cause this configure script to skip all the questions + about non-serial mice. If unsure, say Y. + Logitech busmouse support CONFIG_BUSMOUSE Logitech mouse connected to a proprietary interface card. It's @@ -3236,10 +3357,7 @@ as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. If you are unsure, say N and read the - HOWTO nevertheless: it will tell you what you have. Chances are that - you have a regular serial MouseSystem or Microsoft mouse (made by - Logitech) plugging in a COM port (rectangular with 9 or 25 pins) - which is supported automatically. + HOWTO nevertheless: it will tell you what you have. PS/2 mouse (aka "auxiliary device") support CONFIG_PSMOUSE @@ -3248,16 +3366,15 @@ the mouse does not use any serial ports. This port can also be used for other input devices like light pens, tablets, keypads. Compaq, AST and IBM all use this as their mouse port on currently shipping - machines. The trackballs of some laptops are PS/2 mice - also. Although this is not a busmouse, it is explained in detail in - the Busmouse-HOWTO, available via ftp (user: anonymous) in - sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you want to compile this - as a module ( = code which can be inserted in and removed from the - running kernel whenever you want), say M here and read - Documentation/modules.txt. If you are unsure, say N and read the - HOWTO nevertheless: it will tell you what you have. Chances are that - you have a regular serial MouseSystem or Microsoft mouse plugging in - a COM port (9 or 25 pins) which is supported automatically. + machines. The trackballs of some laptops are PS/2 mice also. In + particular, the C&T 82C710 mouse on TI Travelmates is a PS/2 + mouse. Although PS/2 mice are not technically bus mice, they are + explained in detail in the Busmouse-HOWTO, available via ftp (user: + anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you want to + compile this as a module ( = code which can be inserted in and + removed from the running kernel whenever you want), say M here and + read Documentation/modules.txt. If you are unsure, say N and read + the HOWTO nevertheless: it will tell you what you have. C&T 82C710 mouse port support (as on TI Travelmate) CONFIG_82C710_MOUSE @@ -3275,11 +3392,9 @@ want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. If you are unsure, say N and - read the HOWTO nevertheless: it will tell you what you have. Chances - are that you have a regular serial MouseSystem or Microsoft mouse - plugging in a COM port which is supported automatically. Also be aware - several vendors talk about 'Microsoft busmouse' and actually mean PS/2 - busmouse - so count the pins on the connector. + read the HOWTO nevertheless: it will tell you what you have. Also be + aware that several vendors talk about 'Microsoft busmouse' and + actually mean PS/2 busmouse - so count the pins on the connector. ATIXL busmouse support CONFIG_ATIXL_BUSMOUSE @@ -3290,10 +3405,7 @@ compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. If you are unsure, say N and read - the HOWTO nevertheless: it will tell you what you have. Chances are - that you have a regular serial MouseSystem or Microsoft mouse - plugging in a COM port (9 or 25 pins) which is supported - automatically. + the HOWTO nevertheless: it will tell you what you have. Support for user miscellaneous modules CONFIG_UMISC @@ -3459,6 +3571,15 @@ from the running kernel whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. +Berkshire Products PC Watchdog card +CONFIG_PCWATCHDOG + This is the driver for the Berkshire Products PC Watchdog card. This card + simply watches your kernel to make sure it doesn't freeze, and if it does, + it resets your computer after a certain amount of time. This driver is + like the WDT501 driver but for different hardware. The PC watchdog cards + can be ordered from http://www.berkprod.com. Some example rc.local files + are available from ftp.bitgate.com. + Enhanced Real Time Clock Support CONFIG_RTC If you enable this option and create a character special file @@ -3699,7 +3820,8 @@ with the ISDN utility package for example), you will be able to use your Linux box as an ISDN-answering machine. Of course, this must be supported by the lowlevel driver also. Currently, the Teles - driver is the only voice-supporting one. + driver is the only voice-supporting one. See + Documentation/isdn/README.audio for more information. ICN 2B and 4B support CONFIG_ISDN_DRV_ICN @@ -3808,9 +3930,18 @@ # LocalWords: rtc SMP lp Digi Intl RightSwitch DGRS dgrs AFFS Amiga UFS SDL AP # LocalWords: Solaris RISCom riscom syncPPP PCBIT pcbit sparc anu au artoo ufs # LocalWords: hitchcock Crynwr cnam pktdrvr NCSA's CyDROM CyCDROM FreeBSD NeXT -# LocalWords: NeXTstep disklabel disklabels SMD FFS tm AmigaOS diskfiles Un +# LocalWords: NeXTstep disklabel disklabels SMD FFS tm AmigaOS diskfiles Un IQ # LocalWords: Bernd informatik rwth aachen uae affs multihosting bytecode java # LocalWords: applets applet JDK ncsa cabi SNI Alphatronix readme LANs scarab -# LocalWords: winsock RNIS caltech OSPF honour Honouring Mbit Localtalk -# LocalWords: localtalk download Packetwin Baycom baycom interwork ascii JNT -# LocalWords: Camtec +# LocalWords: winsock RNIS caltech OSPF honour Honouring Mbit Localtalk DEFRAG +# LocalWords: Camtec Berkshire +# LocalWords: Camtec proxying indyramp defragment defragmented UDP FAS FASXX +# LocalWords: FastSCSI SIO FDC qlogicfas QLogic qlogicisp setbaycom ife ee LJ +# LocalWords: ethz ch Travelmates ProAudioSpectrum ProAudio SoundMan SB SBPro +# LocalWords: Thunderboard SM OPL FM ADLIB TSR Gravis MPU PSS ADI SW DSP codec +# LocalWords: ADSP ESC ASIC daughtercard GUSMAX MSS NX AdLib Excell Ensoniq YM +# LocalWords: SoundScape Spea MediaTriX AudioTriX WSS OTI ThunderBoard VoxWare +# LocalWords: Soundscape SSCAPE TRIX MediaTrix PnP Maui dsp midixx EIA getty +# LocalWords: mgetty sendfax gert greenie muc lowlevel Lasermate LanManager io +# LocalWords: OOPSes trackball binghamton mobileip ncr IOMAPPED settags ns ser +# LocalWords: setsync NEGO MPARITY diff -ur --new-file old/linux/Documentation/cdrom/00-INDEX new/linux/Documentation/cdrom/00-INDEX --- old/linux/Documentation/cdrom/00-INDEX Thu Jun 6 13:57:43 1996 +++ new/linux/Documentation/cdrom/00-INDEX Mon Aug 12 12:44:46 1996 @@ -21,7 +21,7 @@ optcd - info on the Optics Storage 8000 AT CD-ROM driver sbpcd - - info on the SoundBlaster Pro CD-ROM interface driver. + - info on the SoundBlaster/Panasonic CD-ROM interface driver. sjcd - info on the SANYO CDR-H94A CD-ROM interface driver. sonycd535 diff -ur --new-file old/linux/Documentation/cdrom/aztcd new/linux/Documentation/cdrom/aztcd --- old/linux/Documentation/cdrom/aztcd Sun May 19 14:17:57 1996 +++ new/linux/Documentation/cdrom/aztcd Sat Aug 3 10:46:51 1996 @@ -351,7 +351,7 @@ aztGetQChannelInfo() repeated several times aztGetToc() aztGetQChannelInfo() repeated several times - a list of track informations + a list of track information do_aztcd_request() } azt_transfer() } repeated several times azt_poll } diff -ur --new-file old/linux/Documentation/cdrom/cdrom-standard.tex new/linux/Documentation/cdrom/cdrom-standard.tex --- old/linux/Documentation/cdrom/cdrom-standard.tex Sat May 18 10:15:10 1996 +++ new/linux/Documentation/cdrom/cdrom-standard.tex Wed Aug 14 09:21:03 1996 @@ -1,5 +1,5 @@ \documentclass{article} -\def\version{$Id: cdrom-standard.tex,v 0.6 1996/05/14 15:42:39 david Exp david $} +\def\version{$Id: cdrom-standard.tex,v 0.8 1996/08/10 10:57:16 david Exp $} \evensidemargin=0pt \oddsidemargin=0pt @@ -11,6 +11,7 @@ \def\cdromc{{\tt cdrom.c}} \def\cdromh{{\tt cdrom.h}} \def\ucdrom{{\tt ucdrom.h}} +\def\fo{\sl} \everymath{\it} \everydisplay{\it} \catcode `\_=\active \def_{\_\penalty100 } @@ -33,82 +34,103 @@ write a driver for Linux (source code examples). \end{itemize} The vast choice and openness has lead not only to a wide support of -hardware devices, but also to a certain divergence in behavior. Especially -for \cdrom\ devices, the way a particular drive reacts to a `standard' -$ioctl()$ call varies a lot from one brand to another; until today, the -\linux\ \cdrom\ driver writers kept away from wilderness by a good practice: -to evolve a new driver by copying, understanding and changing an existing -one. - -Since the beginning of the \cdrom, many different interfaces developed. -Some of them had their own proprietary design (Sony, Mitsumi, Panasonic), -other manufacturers adopted an existing electrical interface and changed -the functionality (CreativeLabs/SoundBlaster, Teac, Funai) or simply adapted -their drives to one or more of the already existing electrical interfaces -(Aztech, Sanyo, Funai, Vertos, Longshine, Optics Storage and most of the -`NoName' manufacturers). -In cases where a new drive really brought his own interface or used his -own command set and flow control scheme, either a separate driver had to -be written, or an existing driver had to get enhanced. +hardware devices, but also to a certain divergence in behavior. +Especially for \cdrom\ devices, the way a particular drive reacts to a +`standard' $ioctl()$ call varies a lot from one brand to another; +however, the \linux\ \cdrom\ driver writers kept away from wilderness +by the practice of evolving a new driver by copying, understanding and +changing an existing one. + +Since the beginning of the \cdrom, many different interfaces +developed. Some of them had their own proprietary design (Sony, +Mitsumi, Panasonic, Philips), other manufacturers adopted an existing +electrical interface and changed the functionality +(CreativeLabs/SoundBlaster, Teac, Funai) or simply adapted their +drives to one or more of the already existing electrical interfaces +(Aztech, Sanyo, Funai, Vertos, Longshine, Optics Storage and most of +the `NoName' manufacturers). In cases where a new drive really +brought his own interface or used his own command set and flow control +scheme, either a separate driver had to be written, or an existing +driver had to get enhanced. Nowadays, almost all new \cdrom\ types are either ATAPI/IDE or SCSI; it is very unlikely that any manufacturer still will create a new interface, and new drives for the existing proprietary interfaces are -getting rare. -But history has delivered us \cdrom\ support for many different interfaces. +getting rare. But history has delivered us \cdrom\ support for many +different interfaces. -Some of the \linux\ \cdrom\ driver writers look at the existing standard -which is expressed through \cdromh\ as to a rather wild set of -commands and data formats and feel that any structure is lost, and from -this point of view, this documentation shall help to achieve a common -programming interface. +When (in the 1.3.70's) I looked at the existing interface which is +expressed through \cdromh\ it appeared to be a rather wild set of +commands and data formats.\footnote{I cannot recollect what kernel + version I looked at, then, presumably 1.2.13 and 1.3.34---the latest + kernel that I was indirectly involved in.} It seemed that many +features of the interface have been added to include certain specific +capabilities of certain drives, in an {\fo ad hoc\/} manner. More +importantly, it appeared that actual execution of the commands is +different for most of the different drivers: e.g., some drivers close +the tray if an $open()$ call occurs while the tray is unloaded, while +others do not. Some drivers lock the door upon opening the device, to +prevent an incoherent file system, but others don't, to allow software +ejection. Undoubtedly, the capabilities of the different drives vary, +but even when two drives have the same capability the driver behavior +may be different. + +I decided to start a discussion on how to improve uniformity, +addressing all \cdrom-driver developers found in the various driver +files. The reactions encouraged me to write a uniform (compatible) +software level \cdromc\ to which this document is the documentation. +In the mean time, the data structure definitions in \cdromh\ had been +cleaned up a lot---which was very helpful for the new code. -Others---mainly those who used the already existing drivers not only -as a coding example, but also as a `user interface' reference during +\begin{quote} +\small +[Apparently, not all \cdrom\ developers support this initiative. +They---mainly those who used the already existing drivers not only as +a coding example, but also as a `user interface' reference during their own development---have taken care that \cdromh\ reflects a software interface to `user programs' which is unique between all drivers as much as possible; these driver writers will continue to refine the existing \cdromh\ where it seems necessary, and they tend to look if any newly requested functionality isn't already there -before they are ready to define new structures. The sbpcd driver gives -an example that it is possible to let a robot arm play juke +before they are ready to define new structures. The {\tt sbpcd} driver +gives an example that it is possible to let a robot arm play juke box---either with audio or with data CDs---and that it is possible to let the juke box work on even if a disk has fallen upon the floor and the drive door has closed without having a disk inside; without any new software layer or any structures which are not already present in \cdromh. This `other' group of \linux\ \cdrom\ driver writers explicitly does {\em not\/} support the idea to define an additional -software layer between driver and user program. +software layer between driver and user program.]\parfillskip=0pt +\end{quote} -The following text reflects the opinion of the first mentioned \linux\ -\cdrom\ driver writer group only; the other group (not only the `silent -majority') sees this text as a good base for a future documentation of the -existing common \linux\ \cdrom\ programming interface, as it is stated -within \cdromh. Where \cdromh\ needs some external -explanation, this text can give it if the reader is aware that---at least -at the moment---this text claims to be the proposal of something else than -\cdromh. - - -Apart from the somewhat unstructured interfacing with software, the -actual execution of the commands is different for most of the -different drivers: e.g., some drivers close the tray if an $open()$ call -occurs while the tray is unloaded, while others do not. Some drivers lock the -door upon opening the device, to prevent an incoherent file system, -but others don't, to allow software ejection. Undoubtedly, the -capabilities of the different drives vary, but even when two drives have -the same capability the driver behavior may be different. - -Personally, I think that the most important drive interfaces will be -the IDE/ATAPI drives and of course the SCSI drives, but as prices of -hardware drop continuously, it is not unlikely that people will have -more than one \cdrom\ drive, possibly of mixed types. (In December -1994, one of the cheapest \cdrom\ drives was a Philips cm206, a -double-speed proprietary drive. In the months that I was busy writing -a \linux\ driver for it, proprietary drives became old-fashioned and -IDE/ATAPI drives became standard. At the time of writing (April 1996) -the cheapest double speed drive is IDE and at one fifth of the price -of its predecessor. Eight speed drives are available now.) +The effort (\cdromc) of which this is the documentation is {\em not\/} +meant to drive a wedge between two groups of driver developers, but +rather to enable sharing of `strategic code' among drivers. The code +should {\em not\/} be viewed as a new interface to user-level +programs, but rather as a new interface between driver code and +kernel. + +Care is taken that 100\,\% compatibility exists with the data +structures and programmer's interface defined in \cdromh, and in order +not to interfere with ongoing development in \cdromh, any `new' data +structures have been put in a separate header file called \ucdrom. +Because the data structures of \cdromh\ are fully supported, this +documentation may also be of help to the programmers using the +interface defined in \cdromh, but this guide is primarily written to +help \cdrom\ driver developers adapt their code to use the `common +\cdrom' code in \cdromc. + +Personally, I think that the most important hardware interfaces will +be the IDE/ATAPI drives and of course the SCSI drives, but as prices +of hardware drop continuously, it is not unlikely that people will +have more than one \cdrom\ drive, possibly of mixed types. It is +important that these drives behave in the same way. (In December 1994, +one of the cheapest \cdrom\ drives was a Philips cm206, a double-speed +proprietary drive. In the months that I was busy writing a \linux\ +driver for it, proprietary drives became old-fashioned and IDE/ATAPI +drives became standard. At the time of writing (April 1996) the +cheapest double speed drive is IDE and at one fifth of the price of +its predecessor. Eight speed drives are available now.) This document defines (in pre-release versions: proposes) the various $ioctl$s, and the way the drivers should implement this. @@ -125,12 +147,16 @@ used when (at least part of) the \cdrom-device driver authors support the idea, an `I' is used for personal opinions} propose to define another software-level, that separates the $ioctl()$ and $open()$ -implementation from the actual hardware implementation. We believe -that \cdrom\ drives are specific enough (i.e., different from other -block-devices such as floppy or hard disc drives), to define a set of -{\em \cdrom\ device operations}, $_dops$. These are of a -different nature than the classical block-device file operations -$_fops$. +implementation from the actual hardware implementation. Note that we +do not wish to alter the existing application interface defined in +\cdromh, but rather want to re-root the hardware-implementation through +some common code. + +We believe that \cdrom\ drives are specific enough (i.e., different +from other block-devices such as floppy or hard disc drives), to +define a set of {\em \cdrom\ device operations}, +$_dops$. These are of a different nature than the +classical block-device file operations $_fops$. The extra interfacing level routines are implemented in a file \cdromc, and a low-level \cdrom\ driver hands over the interfacing to @@ -198,7 +224,7 @@ \noalign{\medskip} &\llap{const\ }int& capability;& capability flags \cr &int& mask;& mask of capability: disables them \cr - &\llap{$const\ $}float& speed;& maximum speed for reading data \cr + &\llap{$const\ $}int& speed;& maximum speed for reading data \cr &\llap{$const\ $}int& minors;& number of supported minor devices \cr &\llap{$const\ $}int& capacity;& number of discs in jukebox \cr \noalign{\medskip} @@ -661,7 +687,7 @@ user can replace it. \end{description} We hope that these option can convince everybody (both driver -maintainers and user program developers) to adapt to the new cdrom +maintainers and user program developers) to adapt to the new \cdrom\ driver scheme and option flag interpretation. \section{Description of routines in \cdromc} @@ -791,7 +817,7 @@ First disc is numbered 0. The number $arg$ is checked against the maximum number of discs in the juke-box found in the $cdrom_dops$. \item[CDROM_MEDIA_CHANGED] Returns 1 if a disc has been changed since - the last call. Note that calls to cdrom_$media_changed$ by the VFS + the last call. Note that calls to $cdrom_media_changed$ by the VFS are treated by an independent queue, so both mechanisms will detect a media change once. Currently, \cdromc\ implements maximum 16 minors per major device. @@ -817,7 +843,7 @@ \item Get hold of the files \cdromc\ and \ucdrom, they should be in the directory tree that came with this documentation. \item Include {\tt \char`\} just after {\tt cdrom.h}. -\item change the 3rd argument of $register_blkdev$ from +\item Change the 3rd argument of $register_blkdev$ from $\&_fops$ to $\&cdrom_fops$. \item Just after that line, add a line to register to the \cdrom\ routines: diff -ur --new-file old/linux/Documentation/cdrom/ide-cd new/linux/Documentation/cdrom/ide-cd --- old/linux/Documentation/cdrom/ide-cd Sun May 19 14:16:34 1996 +++ new/linux/Documentation/cdrom/ide-cd Mon Jul 8 12:01:29 1996 @@ -36,9 +36,9 @@ with the ATAPI 2.6 draft standard (such as the NEC CDR-251). This merely adds a function to switch between the slots of the changer under control of an external program. A sample such program is - appended to the end of this file. I've heard that the Sanyo 3-disc - changer does not conform to this standard, so the changer functions - will probably not work with that drive. + appended to the end of this file. The Sanyo 3-disc changer + (which does not conform to the standard) is also now supported. + Please note the driver refers to the first CD as slot # 0. 2. Installation diff -ur --new-file old/linux/Documentation/devices.tex new/linux/Documentation/devices.tex --- old/linux/Documentation/devices.tex Mon May 13 06:16:49 1996 +++ new/linux/Documentation/devices.tex Wed Jul 10 12:11:40 1996 @@ -42,7 +42,7 @@ % \title{{\bf Linux Allocated Devices}} \author{Maintained by H. Peter Anvin $<$hpa@zytor.com$>$} -\date{Last revised: May 12, 1996} +\date{Last revised: July 9, 1996} \maketitle % \noindent @@ -64,7 +64,9 @@ where that applies (e.g.\ busmice), please contact me with the appropriate device information. Also, if you have additional information regarding any of the devices listed below, or if I have -made a mistake, I would greatly appreciate a note. +made a mistake, I would greatly appreciate a note. When sending me +mail, please include the word ``device'' in the subject so your mail +won't accidentally get buried! Allocations marked (68k/Amiga) apply to Linux/68k on the Amiga platform only. Allocations marked (68k/Atari) apply to Linux/68k on @@ -78,6 +80,10 @@ In particular, please don't sent patches for this list to Linus, at least not without contacting me first. +I do not have any information about these devices beyond what appears +on this list. Any such information requests will be deleted without +reply. + \section{Major numbers} \begin{devicelist} @@ -157,8 +163,9 @@ \major{39}{}{char }{ML-16P experimental I/O board} \major{ }{}{block}{Reserved for Linux/AP+} \major{40}{}{char }{Matrox Meteor frame grabber} -\major{ }{}{block}{Syquest EZ135 removable drive} +\major{ }{}{block}{Syquest EZ135 parallel port removable drive} \major{41}{}{char }{Yet Another Micro Monitor} +\major{ }{}{block}{MicroSolutions BackPack parallel port CD-ROM} \major{42}{}{}{Demo/sample use} \major{43}{}{char }{isdn4linux virtual modem} \major{44}{}{char }{isdn4linux virtual modem -- alternate devices} @@ -169,7 +176,10 @@ \major{49}{}{char }{SDL RISCom serial card -- alternate devices} \major{50}{}{char }{Reserved for GLINT} \major{51}{}{char }{Baycom radio modem} -\major{52}{--59}{}{Unallocated} +\major{52}{}{char }{Spellcaster DataComm/BRI ISDN card} +\major{53}{}{char }{BDM interface for remote debugging MC683xx microcontrollers} +\major{54}{}{char }{Electrocardiognosis Holter serial card} +\major{55}{--59}{}{Unallocated} \major{60}{--63}{}{Local/experimental use} \major{64}{--119}{}{Unallocated} \major{120}{--127}{}{Local/experimental use} @@ -454,6 +464,7 @@ \minor{136}{/dev/qcam0}{QuickCam on {\file lp0}} \minor{137}{/dev/qcam1}{QuickCam on {\file lp1}} \minor{138}{/dev/qcam2}{QuickCam on {\file lp2}} + \minor{139}{/dev/openprom}{SPARC OpenBoot PROM} \end{devicelist} \noindent @@ -972,8 +983,8 @@ \major{40}{}{char }{Matrox Meteor frame grabber} \minor{0}{/dev/mmetfgrab}{Matrox Meteor frame grabber} \\ -\major{ }{}{block}{Syquest EZ135 removable drive} - \minor{0}{/dev/eza}{First EZ135 drive whole disk} +\major{ }{}{block}{Syquest EZ135 parallel port removable drive} + \minor{0}{/dev/eza}{Parallel EZ135 drive whole disk} \end{devicelist} \noindent @@ -983,6 +994,9 @@ \begin{devicelist} \major{41}{}{char }{Yet Another Micro Monitor} \minor{0}{/dev/yamm}{Yet Another Micro Monitor} +\\ +\major{ }{}{block}{MicroSolutions BackPack parallel port CD-ROM} + \minor{0}{/dev/bpcd}{BackPack CD-ROM} \end{devicelist} \begin{devicelist} @@ -1065,7 +1079,44 @@ \end{devicelist} \begin{devicelist} -\major{52}{--59}{}{Unallocated} +\major{52}{}{char }{Spellcaster DataComm/BRI ISDN card} + \minor{0}{/dev/dcbri0}{First DataComm card} + \minor{1}{/dev/dcbri1}{Second DataComm card} + \minor{2}{/dev/dcbri2}{Third DataComm card} + \minor{3}{/dev/dcbri3}{Fourth DataComm card} +\end{devicelist} + +\begin{devicelist} +\major{53}{}{char }{BDM interface for remote debugging MC683xx +microcontrollers} + \minor{0}{/dev/pd\_bdm0}{PD BDM interface on {\file lp0}} + \minor{1}{/dev/pd\_bdm1}{PD BDM interface on {\file lp1}} + \minor{2}{/dev/pd\_bdm2}{PD BDM interface on {\file lp2}} + \minor{4}{/dev/icd\_bdm0}{ICD BDM interface on {\file lp0}} + \minor{5}{/dev/icd\_bdm1}{ICD BDM interface on {\file lp1}} + \minor{6}{/dev/icd\_bdm2}{ICD BDM interface on {\file lp2}} +\end{devicelist} + +\noindent +This device is used for the interfacing to the MC683xx +microcontrollers via Background Debug Mode by use of a Parallel Port +interface. PD is the Motorola Public Domain Interface and ICD is the +commercial interface by P\&E. + +\begin{devicelist} +\major{54}{Electrocardiognosis Holter serial card} + \minor{0}{/dev/holter0}{First Holter port} + \minor{1}{/dev/holter1}{Second Holter port} + \minor{2}{/dev/holter2}{Third Holter port} +\end{devicelist} + +\noindent +A custom serial card used by Electrocardiognosis SRL +$<$mseritan@ottonel.pub.ro$>$ to transfer data from Holter 24-hour +heart monitoring equipment. + +\begin{devicelist} +\major{55}{--59}{}{Unallocated} \end{devicelist} \begin{devicelist} @@ -1119,7 +1170,8 @@ \end{nodelist} \noindent -Note: The last device is: letter {\tt X}-digit {\tt 0}-letter {\tt R}. +Note: The last device is: $<$letter {\tt X}$>$-$<$digit {\tt +0}$>$-$<$letter {\tt R}$>$. \subsection{Recommended links} @@ -1128,6 +1180,7 @@ \begin{nodelist} \link{/dev/core}{/proc/kcore}{symbolic}{Backward compatibility} \link{/dev/ramdisk}{ram0}{symbolic}{Backward compatibility} +\link{/dev/ftape}{rft0}{symbolic}{Backward compatibility} \link{/dev/scd?}{sr?}{hard}{Alternate name for CD-ROMs} %\link{/dev/fd?H*}{fd?D*}{hard}{Compatible floppy formats} %\link{/dev/fd?E*}{fd?D*}{hard}{Compatible floppy formats} diff -ur --new-file old/linux/Documentation/devices.txt new/linux/Documentation/devices.txt --- old/linux/Documentation/devices.txt Mon May 13 06:16:49 1996 +++ new/linux/Documentation/devices.txt Wed Jul 10 12:11:44 1996 @@ -2,7 +2,7 @@ Maintained by H. Peter Anvin - Last revised: May 12, 1996 + Last revised: July 9, 1996 This list is the successor to Rick Miller's Linux Device List, which he stopped maintaining when he got busy with other things in 1993. It @@ -21,7 +21,9 @@ where that applies (e.g. busmice), please contact me with the appropriate device information. Also, if you have additional information regarding any of the devices listed below, or if I have -made a mistake, I would greatly appreciate a note. +made a mistake, I would greatly appreciate a note. When sending me +mail, please include the word "device" in the subject so your mail +won't accidentally get buried! Allocations marked (68k/Amiga) apply to Linux/68k on the Amiga platform only. Allocations marked (68k/Atari) apply to Linux/68k on @@ -35,6 +37,10 @@ In particular, please don't sent patches for this list to Linus, at least not without contacting me first. +I do not have any information about these devices beyond what appears +on this list. Any such information requests will be deleted without +reply. + 0 Unnamed devices (e.g. non-device mounts) 0 = reserved as null device number @@ -274,6 +280,7 @@ 136 = /dev/qcam0 QuickCam on lp0 137 = /dev/qcam1 QuickCam on lp1 138 = /dev/qcam2 QuickCam on lp2 + 139 = /dev/openprom SPARC OpenBoot PROM 11 char Raw keyboard device 0 = /dev/kbd Raw keyboard device @@ -461,7 +468,14 @@ 3 = /dev/sbpcd7 Panasonic CD-ROM controller 1 unit 3 27 char QIC-117 tape - 0 = /dev/ftape QIC-117 tape + 0 = /dev/rft0 Unit 0, rewind-on-close + 1 = /dev/rft1 Unit 1, rewind-on-close + 2 = /dev/rft2 Unit 2, rewind-on-close + 3 = /dev/rft3 Unit 3, rewind-on-close + 4 = /dev/nrft0 Unit 0, no rewind-on-close + 5 = /dev/nrft1 Unit 1, no rewind-on-close + 6 = /dev/nrft2 Unit 2, no rewind-on-close + 7 = /dev/nrft3 Unit 3, no rewind-on-close block Third Matsushita (Panasonic/SoundBlaster) CD-ROM 0 = /dev/sbpcd8 Panasonic CD-ROM controller 2 unit 0 1 = /dev/sbpcd9 Panasonic CD-ROM controller 2 unit 1 @@ -670,14 +684,16 @@ 40 char Matrox Meteor frame grabber 0 = /dev/mmetfgrab Matrox Meteor frame grabber - block Syquest EZ135 removable drive - 0 = /dev/eza First EZ135 drive, whole disk + block Syquest EZ135 parallel port removable drive + 0 = /dev/eza Parallel EZ135 drive, whole disk Partitions are handled in the same way as IDE disks (see major number 3). 41 char Yet Another Micro Monitor 0 = /dev/yamm Yet Another Micro Monitor + block MicroSolutions BackPack parallel port CD-ROM + 0 = /dev/bpcd BackPack CD-ROM 42 Demo/sample use @@ -740,7 +756,36 @@ 1 = /dev/bc1 Second Baycom radio modem ... - 52-59 UNALLOCATED + 52 char Spellcaster DataComm/BRI ISDN card + 0 = /dev/dcbri0 First DataComm card + 1 = /dev/dcbri1 Second DataComm card + 2 = /dev/dcbri2 Third DataComm card + 3 = /dev/dcbri3 Fourth DataComm card + + 53 char BDM interface for remote debugging MC683xx microcontrollers + 0 = /dev/pd_bdm0 PD BDM interface on lp0 + 1 = /dev/pd_bdm1 PD BDM interface on lp1 + 2 = /dev/pd_bdm2 PD BDM interface on lp2 + 4 = /dev/icd_bdm0 ICD BDM interface on lp0 + 5 = /dev/icd_bdm1 ICD BDM interface on lp1 + 6 = /dev/icd_bdm2 ICD BDM interface on lp2 + + This device is used for the interfacing to the MC683xx + microcontrollers via Background Debug Mode by use of a + Parallel Port interface. PD is the Motorola Public + Domain Interface and ICD is the commercial interface + by P&E. + + 54 char Electrocardiognosis Holter serial card + 0 = /dev/holter0 First Holter port + 1 = /dev/holter1 Second Holter port + 2 = /dev/holter2 Third Holter port + + A custom serial card used by Electrocardiognosis SRL + to transfer data from Holter + 24-hour heart monitoring equipment. + + 55-59 UNALLOCATED 60-63 LOCAL/EXPERIMENTAL USE Allocated for local/experimental use. For devices not @@ -780,7 +825,7 @@ /dev/nfsd socksys symbolic Required by iBCS-2 /dev/X0R null symbolic Required by iBCS-2 -Note: the last device is letter X-digit 0-letter R. +Note: the last device is --. Recommended links @@ -788,6 +833,7 @@ /dev/core /proc/kcore symbolic Backward compatibility /dev/ramdisk ram0 symbolic Backward compatibility +/dev/ftape rft0 symbolic Backward compatibility /dev/scd? sr? hard Alternate SCSI CD-ROM name diff -ur --new-file old/linux/Documentation/digiboard.txt new/linux/Documentation/digiboard.txt --- old/linux/Documentation/digiboard.txt Sat Apr 20 10:25:31 1996 +++ new/linux/Documentation/digiboard.txt Thu Aug 1 14:31:04 1996 @@ -45,8 +45,8 @@ # mkdigidev [] # -DIGI_MAJOR=22 -DIGICU_MAJOR=23 +DIGI_MAJOR=23 +DIGICU_MAJOR=22 BOARDS=$1 @@ -60,8 +60,8 @@ for c in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do name=`expr $boardnum \* 16 + $c` - mknod /dev/cud$name c $DIGIMAJOR $name - mknod /dev/ttyD$name c $DIGICUMAJOR $name + mknod /dev/cud$name c $DIGI_CUMAJOR $name + mknod /dev/ttyD$name c $DIGI_MAJOR $name done boardnum=`expr $boardnum + 1` done @@ -97,7 +97,7 @@ + digi) + major1=`Major ttyD` || continue + major2=`Major cud` || continue -+ for i in 0 1 2 3 4 5 6 7 # 8 9 10 11 12 13 14 15 ++ for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + do + makedev ttyD$i c $major1 `expr 32 + $i` $tty + makedev cud$i c $major2 `expr 32 + $i` $dialout @@ -152,3 +152,4 @@ does it want to initialize it. At least not the EISA version. Mike McLagan 5, April 1996. + diff -ur --new-file old/linux/Documentation/filesystems/affs.txt new/linux/Documentation/filesystems/affs.txt --- old/linux/Documentation/filesystems/affs.txt Sun May 19 14:22:19 1996 +++ new/linux/Documentation/filesystems/affs.txt Thu Jul 25 08:08:28 1996 @@ -1,26 +1,28 @@ Amiga filesystems Overview ========================== -Not all varieties of the Amiga filesystems are supported. The Amiga -currently knows 6 different filesystems: +Not all varieties of the Amiga filesystems are supported for reading and +writing. The Amiga currently knows 6 different filesystems: DOS\0 The old or original filesystem, not really suited for hard disks and normally not used on them, either. + Supported read/write. -DOS\1 The original Fast File System. Supported. +DOS\1 The original Fast File System. Supported read/write. DOS\2 The old "international" filesystem. International means that a bug has been fixed so that accented ("international") letters in file names are case-insensitive, as they ought to be. + Supported read/write. -DOS\3 The "international" Fast File System. Supported. +DOS\3 The "international" Fast File System. Supported read/write. DOS\4 The original filesystem with directory cache. The directory cache speeds up directory accesses on floppies considerably, but slows down file creation/deletion. Doesn't make much - sense on hard disks. Not supported. + sense on hard disks. Supported read only. -DOS\5 The Fast File System with directory cache. Not supported. +DOS\5 The Fast File System with directory cache. Supported read only. All of the above filesystems allow block sizes from 512 to 32K bytes. Supported block sizes are: 512, 1024, 2048 and 4096 bytes. Larger blocks @@ -47,9 +49,6 @@ setgid[=gid] Same as above, but for gid. -use_mp The uid and gid are taken from the now covered mount point - instead of the current user or value defined. - mode=mode Sets the mode flags to the given (octal) value, regardless of the original permissions. Directories will get an x permission, if the corresponding r bit is set. @@ -72,6 +71,13 @@ verbose The volume name, file system type and block size will be written to the syslog. +prefix=path Path will be prefixed to every absolute path name of + symbolic links on an AFFS partition. Default = / + +volume=name When symbolic links with an absolute path are created + on an AFFS partition, volume will be prepended as the + volume name. Default = "" (empty string). + Handling of the Users/Groups and protection flags ================================================= @@ -109,9 +115,33 @@ Newly created files and directories will get the user and group id of the current user and a mode according to the umask. -Command line example -==================== - mount Archive/Amiga/Workbench3.1.adf /mnt -t affs -o loop,size=1760 +Symbolic links +============== + +Although the Amiga and Linux file systems resemble each other, there +are some, not always subtle, differences. One of them becomes apparent +with symbolic links. While Linux has a file system with exactly one +root directory, the Amiga has a seperate root directory for each +file system (i. e. partition, floppy disk, ...). With the Amiga, +these entities are called "volumes". They have symbolic names which +can be used to access them. Thus, symbolic links can point to a +different volume. AFFS turns the volume name into a directory name +and prepends the prefix path (see prefix option) to it. + +Example: +You mount all your Amiga partitions under /amiga/ (where + is the name of the volume), and you give the option +"prefix=/amiga/" when mounting all your AFFS partitions. (They +might be "User", "WB" and "Graphics", the mount points /amiga/User, +/amiga/WB and /amiga/Graphics). A symbolic link referring to +"User:sc/include/dos/dos.h" will be followed to +"/amiga/User/sc/include/dos/dos.h". + +Examples +======== + +Command line + mount Archive/Amiga/Workbench3.1.adf /mnt -t affs -o loop,reserved=4 mount /dev/sda3 /Amiga -t affs /etc/fstab example @@ -151,7 +181,7 @@ ln -s /bin/true /etc/fs/mkfs.affs It's not possible to read floppy disks with a normal PC or workstation -due to an incompatibility to the Amiga floppy controller. +due to an incompatibility with the Amiga floppy controller. If you are interested in an Amiga Emulator for Linux, look at diff -ur --new-file old/linux/Documentation/ide.txt new/linux/Documentation/ide.txt --- old/linux/Documentation/ide.txt Sun May 12 20:21:04 1996 +++ new/linux/Documentation/ide.txt Wed Aug 7 11:31:22 1996 @@ -1,4 +1,4 @@ -ide.txt -- Information regarding the Enhanced IDE drive in Linux 2.0.x +ide.txt -- Information regarding the Enhanced IDE drive in Linux 2.0.xx =============================================================================== Supported by: Mark Lord -- disks, interfaces, probing @@ -37,8 +37,8 @@ NEW! - support for reliable operation of buggy CMD-640 interfaces - PCI support is automatic when cmd640 support is configured - for VLB, use kernel command line option: ide0=cmd640_vlb - - this support also enables the secondary i/f on most cards - - experimental interface timing parameter support + - this support also enables the secondary i/f when needed + - interface PIO timing & prefetch parameter support NEW! - experimental support for UMC 8672 interfaces NEW! - support for secondary interface on the FGI/Holtek HT-6560B VLB i/f - use kernel command line option: ide0=ht6560 @@ -62,7 +62,7 @@ and direct reads of audio data. NEW! - experimental support for Promise DC4030VL caching interface card NEW! - email thanks/problems to: peterd@pnd-pc.demon.co.uk -NEW! - the hdparm-2.7 package can be used to set PIO modes for some chipsets. +NEW! - the hdparm-3.1 package can be used to set PIO modes for some chipsets. For work in progress, see the comments in ide.c, ide-cd.c, and triton.c. @@ -71,17 +71,28 @@ Look for this support to be added to the kernel soon. -*** IMPORTANT NOTICES (for kernel versions after 1.3.21) +*** IMPORTANT NOTICES: BUGGY IDE CHIPSETS CAN CORRUPT DATA!! *** ================= *** PCI versions of the CMD640 and RZ1000 interfaces are now detected *** automatically at startup when PCI BIOS support is configured. -*** Linux disables the "pre-fetch" or "read-ahead" modes of these interfaces +*** +*** Linux disables the "prefetch" ("readahead") mode of the RZ1000 *** to prevent data corruption possible due to hardware design flaws. -*** Use of the "serialize" option is no longer necessary. +*** +*** For the CMD640, linux disables "IRQ unmasking" (hdparm -u1) on any +*** drive for which the "prefetch" mode of the CMD640 is turned on. +*** If "prefetch" is disabled (hdparm -p8), then "IRQ unmasking" can be +*** used again. +*** +*** For the CMD640, linux disables "32bit I/O" (hdparm -c1) on any drive +*** for which the "prefetch" mode of the CMD640 is turned off. +*** If "prefetch" is enabled (hdparm -p9), then "32bit I/O" can be +*** used again. *** *** The CMD640 is also used on some Vesa Local Bus (VLB) cards, and is *NOT* *** automatically detected by Linux. For safe, reliable operation with such *** interfaces, one *MUST* use the "ide0=cmd640_vlb" kernel option. +*** *** Use of the "serialize" option is no longer necessary. This is the multiple IDE interface driver, as evolved from hd.c. @@ -90,8 +101,8 @@ Primary: ide0, port 0x1f0; major=3; hda is minor=0; hdb is minor=64 Secondary: ide1, port 0x170; major=22; hdc is minor=0; hdd is minor=64 -Tertiary: ide2, port 0x???; major=33; hde is minor=0; hdf is minor=64 -Quaternary: ide3, port 0x???; major=34; hdg is minor=0; hdh is minor=64 +Tertiary: ide2, port 0x1e8; major=33; hde is minor=0; hdf is minor=64 +Quaternary: ide3, port 0x168; major=34; hdg is minor=0; hdh is minor=64 To access devices on the 2nd/3rd/4th interfaces, device entries must first be created in /dev for them. To create such entries, simply run the included @@ -107,11 +118,25 @@ Interfaces beyond the first two are not normally probed for, but may be specified using kernel "command line" options. For example, - ide3=0x1e8,0x3f0,11 /* ioports 0x1e8-0x1ef,0x3f0, irq 11 */ + ide3=0x168,0x36e,10 /* ioports 0x168-0x16f,0x36e, irq 10 */ Normally the irq number need not be specified, as ide.c will probe for it: - ide3=0x1e8,0x3f0 /* ioports 0x1e8-0x1ef,0x3f0 */ + ide3=0x168,0x36e /* ioports 0x168-0x16f,0x36e */ + +The standard port, and irq values are these: + + ide0=0x1f0,0x3f6,14 + ide1=0x170,0x376,15 + ide2=0x1e8,0x3ee,11 + ide3=0x168,0x36e,10 + +Note that the first parameter reserves 8 contiguous ioports, whereas the +second value denotes a single ioport. If in doubt, do a 'cat /proc/ioports'. + +In all probability the device uses these ports and irqs if it is attached +to the appropriate ide channel. Pass the parameter for the correct ide +channel to the kernel, as explained above. Any number of interfaces may share a single IRQ if necessary, at a slight performance penalty, whether on separate cards or a single VLB card. @@ -230,6 +255,16 @@ Not fully supported by all chipset types, and quite likely to cause trouble with older/odd IDE drives. + + "idebus=xx" : inform IDE driver of VESA/PCI bus speed in Mhz, + where "xx" is between 20 and 66 inclusive, + used when tuning chipset PIO modes. + For PCI bus, 25 is correct for a P75 system, + 30 is correct for P90,P120,P180 systems, + and 33 is used for P100,P133,P166 systems. + If in doubt, use idebus=33 for PCI. + As for VLB, it is safest to not specify it. + Bigger values are safer than smaller ones. "idex=noprobe" : do not attempt to access/use this interface "idex=base" : probe for an interface at the addr specified, diff -ur --new-file old/linux/Documentation/ioctl-number.txt new/linux/Documentation/ioctl-number.txt --- old/linux/Documentation/ioctl-number.txt Fri May 31 12:21:44 1996 +++ new/linux/Documentation/ioctl-number.txt Wed Aug 7 11:31:18 1996 @@ -1,5 +1,5 @@ Ioctl Numbers -29 May 1996 +6 Aug 1996 Michael Chastain @@ -50,7 +50,8 @@ (5) When following the convention, the driver code can use generic code to call verify_area to validate parameters. -This table is current to Linux pre2.0.9. +This table lists ioctls visible from user land for Linux/i386. It is +current to Linux 2.0.11. Code Seq# Include File Comments ======================================================== @@ -83,6 +84,7 @@ 'T' all linux/soundcard.h conflict! 'T' all asm-i386/ioctls.h conflict! 'V' all linux/vt.h +'W' 00-1F linux/pcwd.h 'Y' all linux/cyclades.h 'Z' all linux/scc.h version 2.2 of z8530drv 'a' all various, see http://lrcwww.epfl.ch/linux-atm/magic.html @@ -98,6 +100,7 @@ 't' 80-8F linux/isdn_ppp.h 'u' all linux/smb_fs.h 'v' all linux/ext2_fs.h +'w' all CERN SCI driver (in development) 0x89 00-0F asm-i386/sockios.h 0x89 10-FF linux/sockios.h 0x90 00 linux/sbpcd.h diff -ur --new-file old/linux/Documentation/isdn/INTERFACE new/linux/Documentation/isdn/INTERFACE --- old/linux/Documentation/isdn/INTERFACE Sun May 19 14:29:28 1996 +++ new/linux/Documentation/isdn/INTERFACE Sat Jun 29 19:36:22 1996 @@ -1,4 +1,4 @@ -$Id: INTERFACE,v 1.2 1996/05/18 15:58:53 fritz Exp $ +$Id: INTERFACE,v 1.3 1996/06/25 17:52:41 fritz Exp $ Description of the Interface between Linklevel and Hardwarelevel of isdn4linux: @@ -255,7 +255,7 @@ This command is intended for performing ioctl-calls for configuring hardware or similar purposes (setting port-addresses, loading firmware etc.) For this purpose, in the LL all ioctl-calls with an argument - >= ISDN_IOCTL_DRVIOCTL (0x100) will be handed transparently to this + >= IIOCDRVCTL (0x100) will be handed transparently to this function after subtracting 0x100 and placing the result in arg. Example: If a userlevel-program calls ioctl(0x101,...) the function gets @@ -264,7 +264,7 @@ Parameter: driver = driver-Id. command = ISDN_CMD_IOCTL - arg = Original ioctl-cmd - ISDN_IOCTL_DRVIOCTL + arg = Original ioctl-cmd - IIOCDRVCTL num = first bytes filled with (unsigned long)arg Returnvalue: diff -ur --new-file old/linux/Documentation/isdn/README.teles new/linux/Documentation/isdn/README.teles --- old/linux/Documentation/isdn/README.teles Wed Feb 28 07:32:54 1996 +++ new/linux/Documentation/isdn/README.teles Sat Jun 29 19:36:22 1996 @@ -43,8 +43,9 @@ 4 D channel Q.931 (call control messages) 8 D channel Q.921 16 B channel X.75 + 32 Lowlevel (irq and Layer1 stuff) -For example 'teles/telesctrl MyTeles 1 31' enables full +For example 'teles/telesctrl MyTeles 1 63' enables full debugging. Questions diff -ur --new-file old/linux/Documentation/logo.txt new/linux/Documentation/logo.txt --- old/linux/Documentation/logo.txt Sun Jun 9 07:51:02 1996 +++ new/linux/Documentation/logo.txt Sun Jun 9 17:01:04 1996 @@ -1,4 +1,4 @@ -This is the full-colour version of the currenly unofficial Linux logo +This is the full-colour version of the currently unofficial Linux logo ("currently unofficial" just means that there has been no paperwork and that I haven't really announced it yet). It was created by Larry Ewing, and is freely usable as long as you acknowledge Larry as the original diff -ur --new-file old/linux/Documentation/modules.txt new/linux/Documentation/modules.txt --- old/linux/Documentation/modules.txt Fri Jun 7 15:28:46 1996 +++ new/linux/Documentation/modules.txt Sun Jun 9 17:01:04 1996 @@ -148,7 +148,7 @@ Whenever a program wants the kernel to use a feature that is only available as a loadable module, and if the kernel hasn't got the -module installed yet, the kernel will ask the kerneld deamon to take +module installed yet, the kernel will ask the kerneld daemon to take care of the situation and make the best of it. This is what happens: @@ -166,7 +166,7 @@ has decided that the kernel needs. Every module will be configured according to the "options" lines in "/etc/conf.modules". - modprobe exits and kerneld tells the kernel that the request - succeded (or failed...) + succeeded (or failed...) - The kernel uses the freshly installed feature just as if it had been configured into the kernel as a "resident" part. diff -ur --new-file old/linux/Documentation/xterm-linux.xpm new/linux/Documentation/xterm-linux.xpm --- old/linux/Documentation/xterm-linux.xpm Thu Jan 1 01:00:00 1970 +++ new/linux/Documentation/xterm-linux.xpm Sun Jul 14 12:04:53 1996 @@ -0,0 +1,61 @@ +/* XPM */ +/*****************************************************************************/ +/** This pixmap was made by Torsten Poulin - 1996 - torsten@diku.dk **/ +/** It was made by combining xterm-blank.xpm with **/ +/** the wonderfully cute Linux penguin mascot by Larry Ewing. **/ +/** I had to change Larry's penguin a little to make it fit. **/ +/** xterm-blank.xpm contained the following comment: **/ +/** This pixmap is kindly offered by Ion Cionca - 1992 - **/ +/** Swiss Federal Institute of Technology **/ +/** Central Computing Service **/ +/*****************************************************************************/ +static char * image_name [] = { +/**/ +"64 38 8 1", +/**/ +" s mask c none", +". c gray70", +"X c gray85", +"o c gray50", +"O c yellow", +"+ c darkolivegreen", +"@ c white", +"# c black", +" ###### ", +" ######## ", +" ########## ........................... ", +" ########### .XXXXXXXXXXXXXXXXXXXXXXXXXXX. ", +" ########### .XXXXXXXXXXXXXXXXXXXXXXXXXXXXXoo ", +" #@@@#@@@### .XX+++++++++++++++++++++++XXXXoo ", +" #@#@#@#@### .XX++++++++++++++++++++++++XXXooo ", +" #@#####@### .XX++@@+@++@+@@@@++@+++++++XXXooo ", +" ###OOO######.XX++++++++++++++++++++++++XXXoooo ", +" ##OOOOOO####.XX++@@@@+@@+@@@+++++++++++XXXoooo ", +" #O#OOO#O####.XX++++++++++++++++++++++++XXXooooo ", +" ##O###OO####.XX++@@@@@@@@@@+@@@@@++++++XXXooooo ", +" ###OOOO@#####XX++++++++++++++++++++++++XXXooooo ", +" ##@###@@@@####XX++@@@+@@@@+@@++@@@++++++XXXooooo ", +" #@@@@@@@@@@####X++++++++++++++++++++++++XXXooooo ", +" ##@@@@@@@@@@#####++@+++++++++++++++++++++XXXooooo ", +" ###@@@@@@@@@@######+++++++++++++++++++++++XXXooooo ", +" ####@@@@@@@@@@@#####+@@@@+@+@@@+@++++++++++XXXooooo ", +" ###@@@@@@@@@@@@######++++++++++++++++++++++XXXooooo ", +" ##@@@@@@@@@@@@@@#####@+@@@@++++++++++++++++XXXooooo ", +" ###@@@@@@@@@@@@@@######++++++++++++++++++++XXXXoooo ", +" ###@@@@@@@@@@@@@@######XXXXXXXXXXXXXXXXXXXXXXXXooo ", +" ###@@@@@@@@@@@@@@@######XXXXXXXXXXXXXXXXXXXXXXXooo ", +" ###@@@@@@@@@@@@@@@@#####ooooooooooooooooooooooo...oo ", +" ###@@@@@@@@@@@@@@@######.........................ooo ", +" #OO##@@@@@@@@@@@@@#######oooooooooooooooooooooooooooo ", +" #OOO##@@@@@@@@@@@#OO####O#XXXXXXXXXXXXXXXXXXXXXXXoooo.. .. ", +" ###OOOOO##@@@@@@@@@@#OOO#OOO#XXXXXXXXXXXXXX#######XXoooo . .", +" #OOOOOOOO###@@@@@@@@@#OOOOOOO#ooooooooooooooooooooXXXooo . ", +" #OOOOOOOOO###@@@@@@@@@#OOOOOOO##XXXXXXXXXXXXXXXXXooooo . ", +" #OOOOOOOOO#@@@@@@@@###OOOOOOOOO#XXXXXXXXXXXXXXXoo oooooo ", +" #OOOOOOOOO#@@@@@@@####OOOOOOOO#@@@@@@@@@@@XXXXXoo ooooo...o ", +" #OOOOOOOOOOO###########OOOOOO##XXXXXXXXXXXXXXXXoo ooXXXoo..o ", +" ##OOOOOOOOO###########OOOO##@@@@@@@@@@@@@XXXXoo oXXXXX..o ", +" ###OOOO### oXX##OOO#XXXXXXXXXXXXXXXXXXoo o.....oo ", +" #### oooo####oooooooooooooooooooo ooooooo ", +" ", +" "}; diff -ur --new-file old/linux/MAINTAINERS new/linux/MAINTAINERS --- old/linux/MAINTAINERS Sun Jun 9 11:47:01 1996 +++ new/linux/MAINTAINERS Mon Aug 12 12:44:46 1996 @@ -86,7 +86,7 @@ L: linux-net@vger.rutgers.edu S: Maintained -ETHEREXPRESS NETWORK DRIVER +ETHEREXPRESS-16 NETWORK DRIVER P: Philip Blundell M: pjb27@cam.ac.uk L: linux-net@vger.rutgers.edu @@ -150,13 +150,13 @@ EATA-DMA SCSI DRIVER P: Michael Neuffer M: mike@i-Connect.Net -L: linux-scsi@vger.rutgers.edu +L: linux-eata@i-connect.net, linux-scsi@vger.rutgers.edu S: Maintained EATA-PIO SCSI DRIVER P: Michael Neuffer M: mike@i-Connect.Net -L: linux-scsi@vger.rutgers.edu +L: linux-eata@i-connect.net, linux-scsi@vger.rutgers.edu S: Maintained FRAME RELAY DLCI/FRAD (Sangoma drivers too) @@ -172,7 +172,7 @@ S: Odd fixes (e.g., new signatures) SCSI TAPE DRIVER -P: Kai Mdkisara +P: Kai Mäkisara M: Kai.Makisara@metla.fi L: linux-scsi@vger.rutgers.edu S: Maintained @@ -322,6 +322,18 @@ P: Juergen E. Fischer M: Juergen Fischer L: linux-scsi@vger.rutgers.edu +S: Maintained + +SBPCD CDROM DRIVER +P: Eberhard Moenkeberg +M: emoenke@gwdg.de +L: linux-kernel@vger.rutgers.edu +S: Maintained + +NON-IDE/NON-SCSI CDROM DRIVERS [GENERAL] (come on, crew - mark your responsibility) +P: Eberhard Moenkeberg +M: emoenke@gwdg.de +L: linux-kernel@vger.rutgers.edu S: Maintained CREDITS FILE diff -ur --new-file old/linux/Makefile new/linux/Makefile --- old/linux/Makefile Thu Aug 29 16:32:43 1996 +++ new/linux/Makefile Thu Aug 29 16:33:29 1996 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 0 -SUBLEVEL = 0 +SUBLEVEL = 14 ARCH = i386 diff -ur --new-file old/linux/README new/linux/README --- old/linux/README Thu Jun 6 21:23:08 1996 +++ new/linux/README Wed Jun 26 10:05:26 1996 @@ -76,14 +76,14 @@ the current directory, but an alternative directory can be specified as the second argument. - - make sure your /usr/include/linux and /usr/include/asm directories - are just symlinks to the kernel sources: + - 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 linux - rm -rf asm - ln -s /usr/src/linux/include/linux linux + 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: @@ -138,6 +138,9 @@ in your A: drive, and do a "make zdisk". It is also possible to do "make zlilo" if you have lilo installed to suit the kernel makefiles, but you may want to check your particular lilo setup first. + + - if your kernel is too large for "make zImage", use "make bzImage" + instead. - if you configured any of the parts of the kernel as `modules', you will have to do "make modules" followed by "make modules_install". diff -ur --new-file old/linux/arch/alpha/Makefile new/linux/arch/alpha/Makefile --- old/linux/arch/alpha/Makefile Sat Mar 16 12:52:12 1996 +++ new/linux/arch/alpha/Makefile Sun Aug 4 12:37:59 1996 @@ -14,8 +14,12 @@ # enable this for linking under OSF/1: LINKFLAGS = -non_shared -T 0xfffffc0000310000 -N else -# enable this for linking under Linux: -LINKFLAGS = -static -T arch/alpha/vmlinux.lds -N + elf=$(shell if $(LD) --help | grep elf64alpha >/dev/null; then echo yes; fi) + ifeq ($(elf),yes) + LINKFLAGS = -static -Ttext 0xfffffc0000310000 -N + else + LINKFLAGS = -static -T arch/alpha/vmlinux.lds -N + endif # GNU gcc/cc1/as can use pipes instead of temporary files CFLAGS := $(CFLAGS) -pipe endif diff -ur --new-file old/linux/arch/alpha/boot/Makefile new/linux/arch/alpha/boot/Makefile --- old/linux/arch/alpha/boot/Makefile Sat Mar 16 12:52:12 1996 +++ new/linux/arch/alpha/boot/Makefile Sun Aug 4 12:37:59 1996 @@ -12,8 +12,12 @@ # enable this for linking under OSF/1: LINKFLAGS = -non_shared -T 0x20000000 -N else -# enable this for linking under Linux: -LINKFLAGS = -static -T bootloader.lds -N + elf=$(shell if $(LD) --help | grep elf64alpha >/dev/null; then echo yes; fi) + ifeq ($(elf),yes) + LINKFLAGS = -static -Ttext 0x20000000 -N + else + LINKFLAGS = -static -T bootloader.lds -N + endif endif .S.s: @@ -22,13 +26,15 @@ $(CC) -D__ASSEMBLY__ -traditional -c -o $*.o $< OBJECTS = head.o main.o -TARGETS = vmlinux.gz +TARGETS = vmlinux.gz tools/objstrip # also needed by aboot & milo +VMLINUX = $(TOPDIR)/vmlinux +OBJSTRIP = tools/objstrip all: $(TARGETS) @echo Ready to install kernel in $(shell pwd)/vmlinux.gz # normally no need to build these: -rawboot: vmlinux.nh tools/lxboot tools/bootlx vmlinux +rawboot: vmlinux.nh tools/lxboot tools/bootlx msb: tools/lxboot tools/bootlx vmlinux.nh ( cat tools/lxboot tools/bootlx vmlinux.nh ) > /dev/rz0a @@ -51,21 +57,33 @@ # # A raw binary without header. Used by raw boot. # -vmlinux.nh: tools/build - tools/build -v $(TOPDIR)/vmlinux > vmlinux.nh +main.o: ksize.h + +ksize.h: $(OBJSTRIP) vmlinux.nh + echo "#define KERNEL_SIZE `$(OBJSTRIP) -p vmlinux.nh /dev/null`" > $@ + +vmlinux.nh: $(VMLINUX) $(OBJSTRIP) +ifeq ($(elf),yes) + cp $(VMLINUX) vmlinux.stripped + strip vmlinux.stripped # work around ELF binutils bug... + $(OBJSTRIP) -v vmlinux.stripped vmlinux.nh + rm -f vmlinux.stripped +else + $(OBJSTRIP) -v $(VMLINUX) vmlinux.nh +endif vmlinux: $(TOPDIR)/vmlinux cp $(TOPDIR)/vmlinux vmlinux - quickstrip vmlinux + strip vmlinux -tools/lxboot: tools/build - tools/build > tools/lxboot +tools/lxboot: $(OBJSTRIP) bootloader + $(OBJSTRIP) -p bootloader tools/lxboot -tools/bootlx: bootloader tools/build - tools/build -vb bootloader > tools/bootlx +tools/bootlx: bootloader $(OBJSTRIP) + $(OBJSTRIP) -vb bootloader tools/bootlx -tools/build: tools/build.c - $(HOSTCC) tools/build.c -o tools/build +$(OBJSTRIP): $(OBJSTRIP).c + $(HOSTCC) $(OBJSTRIP).c -o $(OBJSTRIP) tools/mkbb: tools/mkbb.c $(HOSTCC) tools/mkbb.c -o tools/mkbb @@ -74,11 +92,11 @@ $(LD) $(LINKFLAGS) \ $(OBJECTS) \ $(LIBS) \ - -o bootloader || \ + -o bootloader && strip bootloader || \ (rm -f bootloader && exit 1) clean: - rm -f $(TARGETS) bootloader bootimage vmlinux.nh tools/build \ + rm -f $(TARGETS) bootloader bootimage vmlinux.nh \ tools/mkbb tools/bootlx tools/lxboot dep: diff -ur --new-file old/linux/arch/alpha/boot/main.c new/linux/arch/alpha/boot/main.c --- old/linux/arch/alpha/boot/main.c Wed May 15 09:49:36 1996 +++ new/linux/arch/alpha/boot/main.c Sun Aug 4 12:37:59 1996 @@ -17,6 +17,8 @@ #include +#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, @@ -152,8 +154,6 @@ flush_tlb_all(); } -extern int _end; - static inline long openboot(void) { char bootdev[256]; @@ -173,7 +173,8 @@ static inline long load(long dev, unsigned long addr, unsigned long count) { char bootfile[256]; - long result; + extern char _end; + long result, boot_size = &_end - (char *) BOOT_ADDR; result = dispatch(CCB_GET_ENV, ENV_BOOTED_FILE, bootfile, 255); if (result < 0) @@ -181,8 +182,9 @@ result &= 255; bootfile[result] = '\0'; if (result) - printk("Boot file specification (%s) not implemented\n", bootfile); - return dispatch(CCB_READ, dev, count, addr, BOOT_SIZE/512 + 1); + printk("Boot file specification (%s) not implemented\n", + bootfile); + return dispatch(CCB_READ, dev, count, addr, boot_size/512 + 1); } /* @@ -219,9 +221,9 @@ } dev &= 0xffffffff; printk("Loading vmlinux ..."); - i = load(dev, START_ADDR, START_SIZE); + i = load(dev, START_ADDR, KERNEL_SIZE); close(dev); - if (i != START_SIZE) { + if (i != KERNEL_SIZE) { printk("Failed (%lx)\n", i); return; } diff -ur --new-file old/linux/arch/alpha/boot/tools/build.c new/linux/arch/alpha/boot/tools/build.c --- old/linux/arch/alpha/boot/tools/build.c Wed May 15 09:49:36 1996 +++ new/linux/arch/alpha/boot/tools/build.c Thu Jan 1 01:00:00 1970 @@ -1,173 +0,0 @@ -/* - * arch/alpha/boot/tools/build.c - * - * Build a bootable image from the vmlinux binary - */ -#include -#include -#include -#include - -#include - -#include - -#define MAXSECT 10 -#define MAXBUF 8192 - -int verbose = 0; -int pad = 0; -char * program = "tools/build"; -char buffer[MAXBUF]; -unsigned long bootblock[64]; -struct filehdr fhdr; -struct aouthdr ahdr; -struct scnhdr shdr[MAXSECT]; - -char * usage = "'build [-b] system > secondary' or 'build > primary'"; - -static void die(char * str) -{ - fprintf(stderr,"%s: %s\n", program, str); - exit(1); -} - -static int comp(struct scnhdr * a, struct scnhdr * b) -{ - return a->s_vaddr - b->s_vaddr; -} - -int main(int argc, char ** argv) -{ - int fd, i; - unsigned long tmp, start; - unsigned long system_start, system_size; - char * infile = NULL; - - system_start = START_ADDR; - system_size = START_SIZE; - if (argc) { - program = *(argv++); - argc--; - } - while (argc > 0) { - if (**argv == '-') { - while (*++*argv) { - switch (**argv) { - case 'b': - system_start = BOOT_ADDR; - system_size = BOOT_SIZE; - pad = 1; - break; - case 'v': - verbose++; - break; - default: - die(usage); - } - } - } else if (infile) - die(usage); - else - infile = *argv; - argv++; - argc--; - } - if (!infile) { - memcpy(bootblock, "Linux Test", 10); - bootblock[60] = BOOT_SIZE / 512; /* count */ - bootblock[61] = 1; /* starting LBM */ - bootblock[62] = 0; /* flags */ - tmp = 0; - for (i = 0 ; i < 63 ; i++) - tmp += bootblock[i]; - bootblock[63] = tmp; - if (write(1, (char *) bootblock, 512) != 512) { - perror("bbwrite"); - exit(1); - } - return 0; - } - fd = open(infile, O_RDONLY); - if (fd < 0) { - perror(infile); - exit(1); - } - if (read(fd, &fhdr, sizeof(struct filehdr)) != sizeof(struct filehdr)) - die("unable to read file header"); - if (fhdr.f_nscns > MAXSECT) - die("Too many sections"); - if (fhdr.f_opthdr != AOUTHSZ) - die("optional header doesn't look like a.out"); - if (read(fd, &ahdr, sizeof(struct aouthdr)) != sizeof(struct aouthdr)) - die("unable to read a.out header"); - for (i = 0 ; i < fhdr.f_nscns ; i++) { - if (read(fd, i+shdr, sizeof(struct scnhdr)) != sizeof(struct scnhdr)) - die("unable to read section header"); - if (shdr[i].s_paddr != shdr[i].s_vaddr) - die("unable to handle different phys/virt addresses"); - if (shdr[i].s_relptr) - die("Unable to handle relocation info"); - if (verbose) { - fprintf(stderr, "section %d (%.8s):\t%lx - %lx (at %x)\n", - i, shdr[i].s_name, - shdr[i].s_vaddr, - shdr[i].s_vaddr + shdr[i].s_size, - shdr[i].s_scnptr); - } - } - qsort(shdr, fhdr.f_nscns, sizeof(shdr[1]), comp); - start = system_start; - for (i = 0 ; i < fhdr.f_nscns ; i++) { - unsigned long size, offset; - memset(buffer, 0, MAXBUF); - if (!strcmp(shdr[i].s_name, ".comment")) - continue; - if (shdr[i].s_vaddr != start) - die("Unordered or badly placed segments"); - size = shdr[i].s_size; - start += size; - offset = shdr[i].s_scnptr; - if (lseek(fd, offset, SEEK_SET) != offset) - die("Unable to seek in in-file"); - while (size > 0) { - unsigned long num = size; - if (num > MAXBUF) - num = MAXBUF; - if (offset) - if (read(fd, buffer, num) != num) - die("partial read"); - if (write(1, buffer, num) != num) - die("partial write"); - size -= num; - } - if (verbose) { - fprintf(stderr, "section %d (%.8s):\t%lx - %lx (at %x)\n", - i, shdr[i].s_name, - shdr[i].s_vaddr, - shdr[i].s_vaddr + shdr[i].s_size, - shdr[i].s_scnptr); - } - } - if (start > system_start + system_size) { - fprintf(stderr, "Boot image too large\n"); - exit(1); - } - if (pad) { - unsigned long count = (system_start + system_size) - start; - memset(buffer, 0, MAXBUF); - while (count > 0) { - int i = MAXBUF; - if (i > count) - i = count; - i = write(1, buffer, i); - if (i <= 0) { - perror("pad write"); - exit(1); - } - count -= i; - } - } - - return 0; -} diff -ur --new-file old/linux/arch/alpha/boot/tools/objstrip.c new/linux/arch/alpha/boot/tools/objstrip.c --- old/linux/arch/alpha/boot/tools/objstrip.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/alpha/boot/tools/objstrip.c Sun Aug 4 12:37:59 1996 @@ -0,0 +1,280 @@ +/* + * arch/alpha/boot/tools/objstrip.c + * + * Strip the object file headers/trailers from an executable (ELF or ECOFF). + * + * Copyright (C) 1996 David Mosberger-Tang. + */ +/* + * Converts an ECOFF or ELF object file into a bootable file. The + * object file must be a OMAGIC file (i.e., data and bss follow immediatly + * behind the text). See DEC "Assembly Language Programmer's Guide" + * documentation for details. The SRM boot process is documented in + * the Alpha AXP Architecture Reference Manual, Second Edition by + * Richard L. Sites and Richard T. Witek. + */ +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#ifdef __ELF__ +# include +# include +#endif + +/* bootfile size must be multiple of BLOCK_SIZE: */ +#define BLOCK_SIZE 512 + +const char * prog_name; + + +void +usage (void) +{ + fprintf(stderr, + "usage: %s [-v] -p file primary\n" + " %s [-vb] file [secondary]\n", prog_name, prog_name); + exit(1); +} + + +int +main (int argc, char *argv[]) +{ + size_t nwritten, tocopy, n, mem_size, fil_size, pad = 0; + int fd, ofd, i, j, verbose = 0, primary = 0; + char buf[8192], *inname; + struct exec * aout; /* includes file & aout header */ + long offset; +#ifdef __ELF__ + struct elfhdr *elf; + struct elf_phdr *elf_phdr; /* program header */ + unsigned long long e_entry; +#endif + + prog_name = argv[0]; + + for (i = 1; i < argc && argv[i][0] == '-'; ++i) { + for (j = 1; argv[i][j]; ++j) { + switch (argv[i][j]) { + case 'v': + verbose = ~verbose; + break; + + case 'b': + pad = BLOCK_SIZE; + break; + + case 'p': + primary = 1; /* make primary bootblock */ + break; + } + } + } + + if (i >= argc) { + usage(); + } + inname = argv[i++]; + + fd = open(inname, O_RDONLY); + if (fd == -1) { + perror("open"); + exit(1); + } + + ofd = 1; + if (i < argc) { + ofd = open(argv[i++], O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (fd == -1) { + perror("open"); + exit(1); + } + } + + if (primary) { + /* generate bootblock for primary loader */ + + unsigned long bb[64], sum = 0; + struct stat st; + off_t size; + int i; + + if (ofd == 1) { + usage(); + } + + if (fstat(fd, &st) == -1) { + perror("fstat"); + exit(1); + } + + size = (st.st_size + BLOCK_SIZE - 1) & ~(BLOCK_SIZE - 1); + memset(bb, 0, sizeof(bb)); + strcpy((char *) bb, "Linux SRM bootblock"); + bb[60] = size / BLOCK_SIZE; /* count */ + bb[61] = 1; /* starting sector # */ + bb[62] = 0; /* flags---must be 0 */ + for (i = 0; i < 63; ++i) { + sum += bb[i]; + } + bb[63] = sum; + if (write(ofd, bb, sizeof(bb)) != sizeof(bb)) { + perror("boot-block write"); + exit(1); + } + printf("%lu\n", size); + return 0; + } + + /* read and inspect exec header: */ + + if (read(fd, buf, sizeof(buf)) < 0) { + perror("read"); + exit(1); + } + +#ifdef __ELF__ + elf = (struct elfhdr *) buf; + + if (elf->e_ident[0] == 0x7f && strncmp(elf->e_ident + 1, "ELF", 3) == 0) { + if (elf->e_type != ET_EXEC) { + fprintf(stderr, "%s: %s is not an ELF executable\n", + prog_name, inname); + exit(1); + } + if (!elf_check_arch(elf->e_machine)) { + fprintf(stderr, "%s: is not for this processor (e_machine=%d)\n", + prog_name, elf->e_machine); + exit(1); + } + if (elf->e_phnum != 1) { + fprintf(stderr, + "%s: %d program headers (forgot to link with -N?)\n", + prog_name, elf->e_phnum); + } + + e_entry = elf->e_entry; + + lseek(fd, elf->e_phoff, SEEK_SET); + if (read(fd, buf, sizeof(*elf_phdr)) != sizeof(*elf_phdr)) { + perror("read"); + exit(1); + } + + elf_phdr = (struct elf_phdr *) buf; + offset = elf_phdr->p_offset; + mem_size = elf_phdr->p_memsz; + fil_size = elf_phdr->p_filesz; + + /* work around ELF bug: */ + if (elf_phdr->p_vaddr < e_entry) { + unsigned long delta = e_entry - elf_phdr->p_vaddr; + offset += delta; + mem_size -= delta; + fil_size -= delta; + elf_phdr->p_vaddr += delta; + } + + if (verbose) { + fprintf(stderr, "%s: extracting %#016lx-%#016lx (at %lx)\n", + prog_name, (long) elf_phdr->p_vaddr, + elf_phdr->p_vaddr + fil_size, offset); + } + } else +#endif + { + aout = (struct exec *) buf; + + if (!(aout->fh.f_flags & COFF_F_EXEC)) { + fprintf(stderr, "%s: %s is not in executable format\n", + prog_name, inname); + exit(1); + } + + if (aout->fh.f_opthdr != sizeof(aout->ah)) { + fprintf(stderr, "%s: %s has unexpected optional header size\n", + prog_name, inname); + exit(1); + } + + if (N_MAGIC(*aout) != OMAGIC) { + fprintf(stderr, "%s: %s is not an OMAGIC file\n", + prog_name, inname); + exit(1); + } + offset = N_TXTOFF(*aout); + fil_size = aout->ah.tsize + aout->ah.dsize; + mem_size = fil_size + aout->ah.bsize; + + if (verbose) { + fprintf(stderr, "%s: extracting %#016lx-%#016lx (at %lx)\n", + prog_name, aout->ah.text_start, + aout->ah.text_start + fil_size, offset); + } + } + + if (lseek(fd, offset, SEEK_SET) != offset) { + perror("lseek"); + exit(1); + } + + if (verbose) { + fprintf(stderr, "%s: copying %lu byte from %s\n", + prog_name, (unsigned long) fil_size, inname); + } + + tocopy = fil_size; + while (tocopy > 0) { + n = tocopy; + if (n > sizeof(buf)) { + n = sizeof(buf); + } + tocopy -= n; + if ((size_t) read(fd, buf, n) != n) { + perror("read"); + exit(1); + } + do { + nwritten = write(ofd, buf, n); + if ((ssize_t) nwritten == -1) { + perror("write"); + exit(1); + } + n -= nwritten; + } while (n > 0); + } + + if (pad) { + mem_size = ((mem_size + pad - 1) / pad) * pad; + } + + tocopy = mem_size - fil_size; + if (tocopy > 0) { + fprintf(stderr, + "%s: zero-filling bss and aligning to %lu with %lu bytes\n", + prog_name, pad, (unsigned long) tocopy); + + memset(buf, 0x00, sizeof(buf)); + do { + n = tocopy; + if (n > sizeof(buf)) { + n = sizeof(buf); + } + nwritten = write(ofd, buf, n); + if ((ssize_t) nwritten == -1) { + perror("write"); + exit(1); + } + tocopy -= nwritten; + } while (tocopy > 0); + } + return 0; +} diff -ur --new-file old/linux/arch/alpha/config.in new/linux/arch/alpha/config.in --- old/linux/arch/alpha/config.in Tue Jun 4 05:06:37 1996 +++ new/linux/arch/alpha/config.in Sun Aug 4 12:38:59 1996 @@ -36,6 +36,7 @@ choice 'Alpha system type' \ "Avanti CONFIG_ALPHA_AVANTI \ Alpha-XL CONFIG_ALPHA_XL \ + Alpha-XLT CONFIG_ALPHA_XLT \ Cabriolet CONFIG_ALPHA_CABRIOLET \ EB66 CONFIG_ALPHA_EB66 \ EB66+ CONFIG_ALPHA_EB66P \ @@ -61,13 +62,13 @@ define_bool CONFIG_ALPHA_APECS y fi if [ "$CONFIG_ALPHA_EB164" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \ - -o "$CONFIG_ALPHA_ALCOR" = "y" ] + -o "$CONFIG_ALPHA_ALCOR" = "y" -o "$CONFIG_ALPHA_XLT" = "y" ] then define_bool CONFIG_PCI y define_bool CONFIG_ALPHA_EV5 y define_bool CONFIG_ALPHA_CIA y else - # EV5 and newer supports all rounding modes in hw: + # EV45 and older do not support all rounding modes in hw: define_bool CONFIG_ALPHA_NEED_ROUNDING_EMULATION y fi @@ -82,7 +83,7 @@ define_bool CONFIG_ALPHA_AVANTI y fi -bool 'Echo console messages on /dev/ttyS1' CONFIG_SERIAL_ECHO +bool 'Echo console messages on /dev/ttyS0 (COM1)' CONFIG_SERIAL_ECHO if [ "$CONFIG_PCI" = "y" ]; then bool 'TGA Console Support' CONFIG_TGA_CONSOLE if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then @@ -121,6 +122,15 @@ fi endmenu fi + +mainmenu_option next_comment +comment 'ISDN subsystem' + +tristate 'ISDN support' CONFIG_ISDN +if [ "$CONFIG_ISDN" != "n" ]; then + source drivers/isdn/Config.in +fi +endmenu mainmenu_option next_comment comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)' diff -ur --new-file old/linux/arch/alpha/defconfig new/linux/arch/alpha/defconfig --- old/linux/arch/alpha/defconfig Fri Jun 7 13:44:14 1996 +++ new/linux/arch/alpha/defconfig Sun Aug 4 13:20:22 1996 @@ -20,26 +20,28 @@ CONFIG_NATIVE=y # CONFIG_ALPHA_AVANTI is not set # CONFIG_ALPHA_XL is not set +# CONFIG_ALPHA_XLT is not set # CONFIG_ALPHA_CABRIOLET is not set # CONFIG_ALPHA_EB66 is not set # CONFIG_ALPHA_EB66P is not set # CONFIG_ALPHA_EB64P is not set -CONFIG_ALPHA_EB164=y +# CONFIG_ALPHA_EB164 is not set # CONFIG_ALPHA_PC164 is not set # CONFIG_ALPHA_JENSEN is not set # CONFIG_ALPHA_NONAME is not set # CONFIG_ALPHA_MIKASA is not set -# CONFIG_ALPHA_ALCOR is not set +CONFIG_ALPHA_ALCOR=y # CONFIG_ALPHA_P2K is not set CONFIG_PCI=y CONFIG_ALPHA_EV5=y CONFIG_ALPHA_CIA=y +CONFIG_ALPHA_SRM=y # CONFIG_SERIAL_ECHO is not set -# CONFIG_TGA_CONSOLE is not set +CONFIG_TGA_CONSOLE=y CONFIG_NET=y CONFIG_SYSVIPC=y CONFIG_BINFMT_AOUT=y -# CONFIG_BINFMT_ELF is not set +CONFIG_BINFMT_ELF=y # # Floppy, IDE, and other block devices @@ -60,6 +62,7 @@ CONFIG_BLK_DEV_RAM=y # CONFIG_BLK_DEV_INITRD is not set # CONFIG_BLK_DEV_XD is not set +# CONFIG_BLK_DEV_HD is not set # # Networking options @@ -126,13 +129,12 @@ # CONFIG_SCSI_FUTURE_DOMAIN is not set # CONFIG_SCSI_GENERIC_NCR5380 is not set # CONFIG_SCSI_NCR53C406A is not set -CONFIG_SCSI_NCR53C7xx=y -CONFIG_SCSI_NCR53C7xx_sync=y -CONFIG_SCSI_NCR53C7xx_FAST=y -# CONFIG_SCSI_NCR53C7xx_DISCONNECT is not set +# CONFIG_SCSI_NCR53C7xx is not set +# CONFIG_SCSI_NCR53C8XX is not set # CONFIG_SCSI_PPA is not set # CONFIG_SCSI_PAS16 is not set # CONFIG_SCSI_QLOGIC_FAS is not set +CONFIG_SCSI_QLOGIC_ISP=y # CONFIG_SCSI_SEAGATE is not set # CONFIG_SCSI_T128 is not set # CONFIG_SCSI_U14_34F is not set @@ -161,6 +163,11 @@ # CONFIG_NET_POCKET is not set # CONFIG_TR is not set # CONFIG_ARCNET is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set # # CD-ROM drivers (not for SCSI or IDE/ATAPI drives) diff -ur --new-file old/linux/arch/alpha/kernel/apecs.c new/linux/arch/alpha/kernel/apecs.c --- old/linux/arch/alpha/kernel/apecs.c Tue Jun 4 05:06:37 1996 +++ new/linux/arch/alpha/kernel/apecs.c Tue Jul 9 07:08:18 1996 @@ -491,27 +491,30 @@ struct pt_regs * regs) { struct el_common *mchk_header; + struct el_procdata *mchk_procdata; struct el_apecs_sysdata_mcheck *mchk_sysdata; + unsigned long *ptr; + int i; - mchk_header = (struct el_common *)la_ptr; + mchk_header = (struct el_common *)la_ptr; + mchk_procdata = (struct el_procdata *) + (la_ptr + mchk_header->proc_offset - sizeof(mchk_procdata->paltemp)); mchk_sysdata = (struct el_apecs_sysdata_mcheck *)(la_ptr + mchk_header->sys_offset); - DBG(("apecs_machine_check: vector=0x%lx la_ptr=0x%lx\n", vector, la_ptr)); - DBG((" pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n", - regs->pc, mchk_header->size, mchk_header->proc_offset, mchk_header->sys_offset)); - DBG(("apecs_machine_check: expected %d DCSR 0x%lx PEAR 0x%lx\n", - apecs_mcheck_expected, mchk_sysdata->epic_dcsr, mchk_sysdata->epic_pear)); #ifdef DEBUG - { - unsigned long *ptr; - int i; - - ptr = (unsigned long *)la_ptr; - for (i = 0; i < mchk_header->size / sizeof(long); i += 2) { + printk("apecs_machine_check: vector=0x%lx la_ptr=0x%lx\n", + vector, la_ptr); + printk(" pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n", + regs->pc, mchk_header->size, mchk_header->proc_offset, + mchk_header->sys_offset); + printk("apecs_machine_check: expected %d DCSR 0x%lx PEAR 0x%lx\n", + apecs_mcheck_expected, mchk_sysdata->epic_dcsr, + mchk_sysdata->epic_pear); + ptr = (unsigned long *)la_ptr; + for (i = 0; i < mchk_header->size / sizeof(long); i += 2) { printk(" +%lx %lx %lx\n", i*sizeof(long), ptr[i], ptr[i+1]); - } } #endif /* DEBUG */ @@ -520,9 +523,13 @@ * ignore the machine check. */ #ifdef CONFIG_ALPHA_MIKASA - /* for now on MIKASA, if it was expected, ignore it */ - /* we need the details of the mcheck frame to really know... */ - if (apecs_mcheck_expected) { +#define MCHK_NO_DEVSEL 0x205L +#define MCHK_NO_TABT 0x204L + if (apecs_mcheck_expected && + (((unsigned int)mchk_procdata->paltemp[0] == MCHK_NO_DEVSEL) || + ((unsigned int)mchk_procdata->paltemp[0] == MCHK_NO_TABT)) + ) + { #else if (apecs_mcheck_expected && (mchk_sysdata->epic_dcsr && 0x0c00UL)) { #endif @@ -534,7 +541,33 @@ wrmces(0x7); mb(); draina(); + DBG(("apecs_machine_check: EXPECTED\n")); + } + else if (vector == 0x620 || vector == 0x630) { + wrmces(0x1f); /* disable correctable from now on */ + mb(); + draina(); + printk("apecs_machine_check: HW correctable (0x%lx)\n", vector); + } + else { + printk("APECS machine check:\n"); + printk(" vector=0x%lx la_ptr=0x%lx\n", + vector, la_ptr); + printk(" pc=0x%lx size=0x%x procoffset=0x%x sysoffset 0x%x\n", + regs->pc, mchk_header->size, mchk_header->proc_offset, + mchk_header->sys_offset); + printk(" expected %d DCSR 0x%lx PEAR 0x%lx\n", + apecs_mcheck_expected, mchk_sysdata->epic_dcsr, + mchk_sysdata->epic_pear); + + ptr = (unsigned long *)la_ptr; + for (i = 0; i < mchk_header->size / sizeof(long); i += 2) { + printk(" +%lx %lx %lx\n", i*sizeof(long), ptr[i], ptr[i+1]); + } +#if 0 + /* doesn't work with MILO */ + show_regs(regs); +#endif } } - #endif /* CONFIG_ALPHA_APECS */ diff -ur --new-file old/linux/arch/alpha/kernel/bios32.c new/linux/arch/alpha/kernel/bios32.c --- old/linux/arch/alpha/kernel/bios32.c Sat Jun 8 10:24:57 1996 +++ new/linux/arch/alpha/kernel/bios32.c Wed Aug 7 11:31:21 1996 @@ -892,6 +892,62 @@ common_fixup(7, 12, 5, irq_tab, 0); } +/* + * Fixup configuration for ALPHA XLT (EV5/EV56) + * + * Summary @ GRU_INT_REQ: + * Bit Meaning + * 0 Interrupt Line A from slot 2 + * 1 Interrupt Line B from slot 2 + * 2 Interrupt Line C from slot 2 + * 3 Interrupt Line D from slot 2 + * 4 Interrupt Line A from slot 1 + * 5 Interrupt line B from slot 1 + * 6 Interrupt Line C from slot 1 + * 7 Interrupt Line D from slot 1 + * 8 Interrupt Line A from slot 0 + * 9 Interrupt Line B from slot 0 + *10 Interrupt Line C from slot 0 + *11 Interrupt Line D from slot 0 + *12 NCR810 SCSI in slot 9 + *13 DC-21040 (TULIP) in slot 6 + *14-19 Reserved + *20-23 Jumpers (interrupt) + *24-27 Module revision + *28-30 Reserved + *31 EISA interrupt + * + * The device to slot mapping looks like: + * + * Slot Device + * 6 TULIP + * 7 PCI on board slot 0 + * 8 none + * 9 SCSI + * 10 PCI-ISA bridge + * 11 PCI on board slot 2 + * 12 PCI on board slot 1 + * + * + * This two layered interrupt approach means that we allocate IRQ 16 and + * above for PCI interrupts. The IRQ relates to which bit the interrupt + * comes in on. This makes interrupt processing much easier. + */ +static inline void xlt_fixup(void) +{ + char irq_tab[7][5] = { + /*INT INTA INTB INTC INTD */ + {16+13, 16+13, 16+13, 16+13, 16+13}, /* IdSel 17, TULIP */ + { 16+8, 16+8, 16+9, 16+10, 16+11}, /* IdSel 18, slot 0 */ + { -1, -1, -1, -1, -1}, /* IdSel 19, none */ + {16+12, 16+12, 16+12, 16+12, 16+12}, /* IdSel 20, SCSI */ + { -1, -1, -1, -1, -1}, /* IdSel 21, SIO */ + { 16+0, 16+0, 16+1, 16+2, 16+3}, /* IdSel 22, slot 2 */ + { 16+4, 16+4, 16+5, 16+6, 16+7}, /* IdSel 23, slot 1 */ + }; + common_fixup(6, 12, 5, irq_tab, 0); +} + /* * Fixup configuration for all boards that route the PCI interrupts @@ -937,6 +993,7 @@ { 0, 0, 2, 1, 0}, /* idsel 11 KN25_PCI_SLOT0 */ { 1, 1, 0, 2, 1}, /* idsel 12 KN25_PCI_SLOT1 */ { 2, 2, 1, 0, 2}, /* idsel 13 KN25_PCI_SLOT2 */ + { 0, 0, 0, 0, 0}, /* idsel 14 AS255 TULIP */ #endif }; /* @@ -949,7 +1006,21 @@ * This probably ought to be configurable via MILO. For * example, sound boards seem to like using IRQ 9. */ +#ifdef CONFIG_ALPHA_NONAME + /* + * For UDB, the only available PCI slot must not map to IRQ 9, + * since that's the builtin MSS sound chip. That PCI slot + * will map to PIRQ1 (for INTA at least), so we give it IRQ 15 + * instead. + * + * Unfortunately we have to do this for NONAME as well, since + * they are co-indicated when the platform type "Noname" is + * selected... :-( + */ + const unsigned int route_tab = 0x0b0a0f09; +#else /* CONFIG_ALPHA_NONAME */ const unsigned int route_tab = 0x0b0a090f; +#endif /* CONFIG_ALPHA_NONAME */ unsigned int level_bits; unsigned char pin, slot; int pirq; @@ -1037,8 +1108,13 @@ * Now, make all PCI interrupts level sensitive. Notice: * these registers must be accessed byte-wise. inw()/outw() * don't work. + * + * Make sure to turn off any level bits set for IRQs 9,10,11,15, + * so that the only bits getting set are for devices actually found. + * Note that we do preserve the remainder of the bits, which we hope + * will be set correctly by ARC/SRM. */ - level_bits |= (inb(0x4d0) | (inb(0x4d1) << 8)); + level_bits |= ((inb(0x4d0) | (inb(0x4d1) << 8)) & 0x71ff); outb((level_bits >> 0) & 0xff, 0x4d0); outb((level_bits >> 8) & 0xff, 0x4d1); enable_ide(0x26e); @@ -1077,6 +1153,8 @@ mikasa_fixup(); #elif defined(CONFIG_ALPHA_ALCOR) alcor_fixup(); +#elif defined(CONFIG_ALPHA_XLT) + xlt_fixup(); #else # error You must tell me what kind of platform you want. #endif diff -ur --new-file old/linux/arch/alpha/kernel/head.S new/linux/arch/alpha/kernel/head.S --- old/linux/arch/alpha/kernel/head.S Fri Dec 22 07:22:04 1995 +++ new/linux/arch/alpha/kernel/head.S Mon Jul 1 19:06:05 1996 @@ -10,7 +10,7 @@ #define __ASSEMBLY__ #include -#define halt .long PAL_halt +#define halt call_pal PAL_halt .globl swapper_pg_dir .globl _stext @@ -32,7 +32,7 @@ .globl wrent .ent wrent wrent: - .long PAL_wrent + call_pal PAL_wrent ret ($26) .end wrent @@ -40,7 +40,7 @@ .globl wrkgp .ent wrkgp wrkgp: - .long PAL_wrkgp + call_pal PAL_wrkgp ret ($26) .end wrkgp @@ -48,7 +48,7 @@ .globl wrusp .ent wrusp wrusp: - .long PAL_wrusp + call_pal PAL_wrusp ret ($26) .end wrusp @@ -56,7 +56,7 @@ .globl rdusp .ent rdusp rdusp: - .long PAL_rdusp + call_pal PAL_rdusp ret ($26) .end rdusp @@ -64,7 +64,7 @@ .globl tbi .ent tbi tbi: - .long PAL_tbi + call_pal PAL_tbi ret ($26) .end tbi @@ -72,7 +72,7 @@ .globl imb .ent imb imb: - .long PAL_imb + call_pal PAL_imb ret ($26) .end imb diff -ur --new-file old/linux/arch/alpha/kernel/irq.c new/linux/arch/alpha/kernel/irq.c --- old/linux/arch/alpha/kernel/irq.c Sat Jun 8 10:24:57 1996 +++ new/linux/arch/alpha/kernel/irq.c Wed Aug 7 11:31:22 1996 @@ -28,109 +28,86 @@ extern void timer_interrupt(struct pt_regs * regs); -static unsigned char cache_21 = 0xff; -static unsigned char cache_A1 = 0xff; - -#if NR_IRQS == 48 - static unsigned int cache_irq_mask = 0x7fffffff; /* enable EISA */ -#elif NR_IRQS == 33 - static unsigned int cache_804 = 0x00ffffef; -#elif NR_IRQS == 32 -#ifdef CONFIG_ALPHA_MIKASA - static unsigned short cache_536 = 0xffff; -#else - static unsigned char cache_26 = 0xdf; - static unsigned char cache_27 = 0xff; -#endif +#if NR_IRQS > 64 +# error Unable to handle more than 64 irq levels. #endif -static void mask_irq(int irq) -{ - unsigned long mask; +/* Reserved interrupts. These must NEVER be requested by any driver! + */ +#define IS_RESERVED_IRQ(irq) ((irq)==2) /* IRQ 2 used by hw cascade */ - if (irq < 16) { - mask = 1 << (irq & 7); - if (irq < 8) { - cache_21 |= mask; - outb(cache_21, 0x21); - } else { - cache_A1 |= mask; - outb(cache_A1, 0xA1); - } +/* + * Shadow-copy of masked interrupts. + * The bits are used as follows: + * 0.. 7 first (E)ISA PIC (irq level 0..7) + * 8..15 second (E)ISA PIC (irq level 8..15) + * Systems with PCI interrupt lines managed by GRU (e.g., Alcor, XLT): + * 16..47 PCI interrupts 0..31 (int at GRU_INT_MASK) + * Mikasa: + * 16..31 PCI interrupts 0..15 (short at I/O port 536) + * Other systems (not Mikasa) with 16 PCI interrupt lines: + * 16..23 PCI interrupts 0.. 7 (char at I/O port 26) + * 24..31 PCI interrupts 8..15 (char at I/O port 27) + * Systems with 17 PCI interrupt lines (e.g., Cabriolet and eb164): + * 16..32 PCI interrupts 0..31 (int at I/O port 804) + */ +static unsigned long irq_mask = ~0UL; + + +/* + * Update the hardware with the irq mask passed in MASK. The function + * exploits the fact that it is known that only bit IRQ has changed. + */ +static void update_hw(unsigned long irq, unsigned long mask) +{ + switch (irq) { #if NR_IRQS == 48 - } else { - mask = 1 << (irq - 16); - cache_irq_mask |= mask; - *(unsigned int *)GRU_INT_MASK = ~cache_irq_mask; /* invert */ + default: + /* note inverted sense of mask bits: */ + *(unsigned int *)GRU_INT_MASK = ~(mask >> 16); mb(); + break; + #elif NR_IRQS == 33 - } else { - mask = 1 << (irq - 16); - cache_804 |= mask; - outl(cache_804, 0x804); + default: + outl(mask >> 16, 0x804); + break; + +#elif defined(CONFIG_ALPHA_MIKASA) + default: + outw(~(mask >> 16), 0x536); /* note invert */ + break; + #elif NR_IRQS == 32 -#ifdef CONFIG_ALPHA_MIKASA - } else { - mask = 1 << (irq & 15); - cache_536 |= mask; - outw(~cache_536, 0x536); /* note invert */ -#else - } else { - mask = 1 << (irq & 7); - if (irq < 24) { - cache_26 |= mask; - outb(cache_26, 0x26); - } else { - cache_27 |= mask; - outb(cache_27, 0x27); - } -#endif + case 16 ... 23: + outb(mask >> 16, 0x26); + break; + + default: + outb(mask >> 24, 0x27); + break; #endif + /* handle ISA irqs last---fast devices belong on PCI... */ + + case 0 ... 7: /* ISA PIC1 */ + outb(mask, 0x21); + break; + + case 8 ...15: /* ISA PIC2 */ + outb(mask >> 8, 0xA1); + break; } } -static void unmask_irq(unsigned long irq) +static inline void mask_irq(unsigned long irq) { - unsigned long mask; - - if (irq < 16) { - mask = ~(1 << (irq & 7)); - if (irq < 8) { - cache_21 &= mask; - outb(cache_21, 0x21); - } else { - cache_A1 &= mask; - outb(cache_A1, 0xA1); - } -#if NR_IRQS == 48 - } else { - mask = ~(1 << (irq - 16)); - cache_irq_mask &= mask; - *(unsigned int *)GRU_INT_MASK = ~cache_irq_mask; /* invert */ -#elif NR_IRQS == 33 - } else { - mask = ~(1 << (irq - 16)); - cache_804 &= mask; - outl(cache_804, 0x804); -#elif NR_IRQS == 32 -#ifdef CONFIG_ALPHA_MIKASA - } else { - mask = ~(1 << (irq & 15)); - cache_536 &= mask; - outw(~cache_536, 0x536); /* note invert */ -#else - } else { - mask = ~(1 << (irq & 7)); + irq_mask |= (1UL << irq); + update_hw(irq, irq_mask); +} - if (irq < 24) { - cache_26 &= mask; - outb(cache_26, 0x26); - } else { - cache_27 &= mask; - outb(cache_27, 0x27); - } -#endif -#endif - } +static inline void unmask_irq(unsigned long irq) +{ + irq_mask &= ~(1UL << irq); + update_hw(irq, irq_mask); } void disable_irq(unsigned int irq_nr) @@ -192,14 +169,12 @@ } /* .. then the master */ outb(0xE0 | irq, 0x20); +#if defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) + /* on ALCOR/XLT, need to dismiss interrupt via GRU */ + *(int *)GRU_INT_CLEAR = 0x80000000; mb(); + *(int *)GRU_INT_CLEAR = 0x00000000; mb(); +#endif /* ALCOR || XLT */ } -#if defined(CONFIG_ALPHA_ALCOR) - /* on ALCOR, need to dismiss interrupt via GRU */ - *(int *)GRU_INT_CLEAR = 0x80000000; - mb(); - *(int *)GRU_INT_CLEAR = 0x00000000; - mb(); -#endif /* CONFIG_ALPHA_ALCOR */ } int request_irq(unsigned int irq, @@ -214,6 +189,8 @@ if (irq >= NR_IRQS) return -EINVAL; + if (IS_RESERVED_IRQ(irq)) + return -EINVAL; if (!handler) return -EINVAL; p = irq_action + irq; @@ -270,6 +247,10 @@ printk("Trying to free IRQ%d\n",irq); return; } + if (IS_RESERVED_IRQ(irq)) { + printk("Trying to free reserved IRQ %d\n", irq); + return; + } for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) { if (action->dev_id != dev_id) continue; @@ -344,17 +325,6 @@ kstat.interrupts[irq]++; action = irq_action[irq]; - if (action) { - /* quick interrupts get executed with no extra overhead */ - if (action->flags & SA_INTERRUPT) { - while (action) { - action->handler(irq, action->dev_id, regs); - action = action->next; - } - ack_irq(ack); - return; - } - } /* * For normal interrupts, we mask it out, and then ACK it. * This way another (more timing-critical) interrupt can @@ -370,10 +340,10 @@ return; if (action->flags & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); - while (action) { + do { action->handler(irq, action->dev_id, regs); action = action->next; - } + } while (action); unmask_irq(ack); } @@ -436,8 +406,8 @@ * write only. This is not true. */ pic = inb(0x20) | (inb(0xA0) << 8); /* read isr */ - pic &= ~((cache_A1 << 8) | cache_21); /* apply mask */ - pic &= 0xFFFB; /* mask out cascade */ + pic &= ~irq_mask; /* apply mask */ + pic &= 0xFFFB; /* mask out cascade & hibits */ while (pic) { j = ffz(~pic); @@ -447,6 +417,42 @@ #endif } +#if defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) +/* we have to conditionally compile this because of GRU_xxx symbols */ +static inline void alcor_and_xlt_device_interrupt(unsigned long vector, + struct pt_regs * regs) +{ + unsigned long pld; + unsigned int i; + unsigned long flags; + + save_flags(flags); + cli(); + + /* read the interrupt summary register of the GRU */ + pld = (*(unsigned int *)GRU_INT_REQ) & GRU_INT_REQ_BITS; + +#if 0 + printk("[0x%08lx/0x%04x]", pld, inb(0x20) | (inb(0xA0) << 8)); +#endif + + /* + * Now for every possible bit set, work through them and call + * the appropriate interrupt handler. + */ + while (pld) { + i = ffz(~pld); + pld &= pld - 1; /* clear least bit set */ + if (i == 31) { + isa_device_interrupt(vector, regs); + } else { + device_interrupt(16 + i, 16 + i, regs); + } + } + restore_flags(flags); +} +#endif /* ALCOR || XLT */ + static inline void cabriolet_and_eb66p_device_interrupt(unsigned long vector, struct pt_regs * regs) { @@ -480,6 +486,41 @@ restore_flags(flags); } +static inline void mikasa_device_interrupt(unsigned long vector, + struct pt_regs * regs) +{ + unsigned long pld; + unsigned int i; + unsigned long flags; + + save_flags(flags); + cli(); + + /* read the interrupt summary registers */ + pld = (((unsigned long) (~inw(0x534)) & 0x0000ffffUL) << 16) | + (((unsigned long) inb(0xa0)) << 8) | + ((unsigned long) inb(0x20)); + +#if 0 + printk("[0x%08lx]", pld); +#endif + + /* + * Now for every possible bit set, work through them and call + * the appropriate interrupt handler. + */ + while (pld) { + i = ffz(~pld); + pld &= pld - 1; /* clear least bit set */ + if (i < 16) { + isa_device_interrupt(vector, regs); + } else { + device_interrupt(i, i, regs); + } + } + restore_flags(flags); +} + static inline void eb66_and_eb64p_device_interrupt(unsigned long vector, struct pt_regs * regs) { @@ -568,17 +609,13 @@ restore_flags(flags) ; } -#if NR_IRQS > 64 -# error Number of irqs limited to 64 due to interrupt-probing. -#endif - /* * Start listening for interrupts.. */ unsigned long probe_irq_on(void) { struct irqaction * action; - unsigned long irqs = 0, irqmask; + unsigned long irqs = 0; unsigned long delay; unsigned int i; @@ -589,27 +626,15 @@ irqs |= (1 << i); } } - - /* wait for spurious interrupts to mask themselves out again */ + /* + * Wait about 100ms for spurious interrupts to mask themselves + * out again... + */ for (delay = jiffies + HZ/10; delay > jiffies; ) - /* about 100 ms delay */; - + barrier(); + /* now filter out any obviously spurious interrupts */ - irqmask = (((unsigned long)cache_A1)<<8) | (unsigned long) cache_21; -#if NR_IRQS == 48 - irqmask |= (unsigned long) cache_irq_mask << 16; -#elif NR_IRQS == 33 - irqmask |= (unsigned long) cache_804 << 16; -#elif NR_IRQS == 32 -#ifdef CONFIG_ALPHA_MIKASA - irqmask |= (unsigned long) cache_536 << 16; -#else - irqmask |= ((((unsigned long)cache_26)<<16) | - (((unsigned long)cache_27)<<24)); -#endif -#endif - irqs &= ~irqmask; - return irqs; + return irqs & ~irq_mask; } /* @@ -619,23 +644,9 @@ */ int probe_irq_off(unsigned long irqs) { - unsigned long irqmask; int i; - irqmask = (((unsigned int)cache_A1)<<8) | (unsigned int)cache_21; -#if NR_IRQS == 48 - irqmask |= (unsigned long) cache_irq_mask << 16; -#elif NR_IRQS == 33 - irqmask |= (unsigned long) cache_804 << 16; -#elif NR_IRQS == 32 -#ifdef CONFIG_ALPHA_MIKASA - irqmask |= (unsigned long) cache_536 << 16; -#else - irqmask |= ((((unsigned long)cache_26)<<16) | - (((unsigned long)cache_27)<<24)); -#endif -#endif - irqs &= irqmask & ~1; /* always mask out irq 0---it's the unused timer */ + irqs &= irq_mask & ~1; /* always mask out irq 0---it's the unused timer */ #ifdef CONFIG_ALPHA_P2K irqs &= ~(1 << 8); /* mask out irq 8 since that's the unused RTC input to PIC */ #endif @@ -684,14 +695,14 @@ #if defined(CONFIG_ALPHA_JENSEN) || defined(CONFIG_ALPHA_NONAME) || \ defined(CONFIG_ALPHA_P2K) || defined(CONFIG_ALPHA_SRM) srm_device_interrupt(vector, ®s); +#elif NR_IRQS == 48 + alcor_and_xlt_device_interrupt(vector, ®s); #elif NR_IRQS == 33 cabriolet_and_eb66p_device_interrupt(vector, ®s); +#elif defined(CONFIG_ALPHA_MIKASA) + mikasa_device_interrupt(vector, ®s); #elif NR_IRQS == 32 -#ifdef CONFIG_ALPHA_MIKASA -# error we got a problem here Charlie MIKASA should be SRM console -#else eb66_and_eb64p_device_interrupt(vector, ®s); -#endif #elif NR_IRQS == 16 isa_device_interrupt(vector, ®s); #endif @@ -715,16 +726,17 @@ dma_outb(0, DMA1_CLR_MASK_REG); dma_outb(0, DMA2_CLR_MASK_REG); #if NR_IRQS == 48 - *(unsigned int *)GRU_INT_MASK = ~cache_irq_mask; /* invert */ + *(unsigned int *)GRU_INT_MASK = ~(irq_mask >> 16); mb();/* invert */ + enable_irq(16 + 31); /* enable (E)ISA PIC cascade */ #elif NR_IRQS == 33 - outl(cache_804, 0x804); + outl(irq_mask >> 16, 0x804); + enable_irq(16 + 4); /* enable SIO cascade */ +#elif defined(CONFIG_ALPHA_MIKASA) + outw(~(irq_mask >> 16), 0x536); /* note invert */ #elif NR_IRQS == 32 -#ifdef CONFIG_ALPHA_MIKASA - outw(~cache_536, 0x536); /* note invert */ -#else - outb(cache_26, 0x26); - outb(cache_27, 0x27); -#endif + outb(irq_mask >> 16, 0x26); + outb(irq_mask >> 24, 0x27); + enable_irq(16 + 5); /* enable SIO cascade */ #endif enable_irq(2); /* enable cascade */ } diff -ur --new-file old/linux/arch/alpha/kernel/ksyms.c new/linux/arch/alpha/kernel/ksyms.c --- old/linux/arch/alpha/kernel/ksyms.c Tue Apr 23 11:49:55 1996 +++ new/linux/arch/alpha/kernel/ksyms.c Sun Aug 4 12:37:59 1996 @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include @@ -24,6 +26,10 @@ extern void __divqu (void); extern void __remqu (void); +extern void dump_thread(struct pt_regs *, struct user *); +extern int dump_fpu(struct pt_regs *, elf_fpregset_t *); + + static struct symbol_table arch_symbol_table = { #include /* platform dependent support */ @@ -62,11 +68,16 @@ X(strstr), X(strtok), X(strchr), - X(hwrpb), X(memcmp), X(memmove), X(__memcpy), X(__constant_c_memset), + + X(dump_thread), + X(dump_fpu), + X(hwrpb), + X(wrusp), + /* * The following are special because they're not called * explicitly (the C compiler or assembler generates them in diff -ur --new-file old/linux/arch/alpha/kernel/lca.c new/linux/arch/alpha/kernel/lca.c --- old/linux/arch/alpha/kernel/lca.c Sat Feb 17 08:19:37 1996 +++ new/linux/arch/alpha/kernel/lca.c Mon Jul 15 08:47:41 1996 @@ -341,7 +341,7 @@ printk(" %s %s error to %s occurred at address %x\n", (esr & ESR_CEE) ? "Correctable" : ((esr & ESR_UEE) ? "Uncorrectable" : "A"), (esr & ESR_WRE) ? "write" : "read", - (esr & ESR_SOR) ? "b-cache" : "memory", + (esr & ESR_SOR) ? "memory" : "b-cache", (unsigned) (ear & 0x1ffffff8)); if (esr & ESR_CTE) { printk(" A b-cache tag parity error was detected.\n"); diff -ur --new-file old/linux/arch/alpha/kernel/osf_sys.c new/linux/arch/alpha/kernel/osf_sys.c --- old/linux/arch/alpha/kernel/osf_sys.c Fri Apr 12 08:49:30 1996 +++ new/linux/arch/alpha/kernel/osf_sys.c Sun Aug 18 09:42:02 1996 @@ -125,14 +125,22 @@ return count - buf.count; } -asmlinkage int osf_getpriority(int which, int who) +/* + * Alpha syscall convention has no problem returning negative + * values: + */ +asmlinkage int osf_getpriority(int which, int who, int a2, int a3, int a4, + int a5, struct pt_regs regs) { extern int sys_getpriority(int, int); - /* - * Alpha syscall convention has no problem returning negative - * values: - */ - return 20 - sys_getpriority(which, who); + int prio; + + prio = sys_getpriority(which, who); + if (prio < 0) + return prio; + + regs.r0 = 0; /* special return: no errors */ + return 20 - prio; } @@ -177,16 +185,52 @@ if (fd >= NR_OPEN || !(file = current->files->fd[fd])) return -EBADF; } + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); return do_mmap(file, addr, len, prot, flags, off); } -asmlinkage int osf_statfs(char * path, struct statfs * buffer, unsigned long bufsiz) + +/* + * The OSF/1 statfs structure is much larger, but this should + * match the beginning, at least. + */ +struct osf_statfs { + short f_type; + short f_flags; + int f_fsize; + int f_bsize; + int f_blocks; + int f_bfree; + int f_bavail; + int f_files; + int f_ffree; + __kernel_fsid_t f_fsid; +} * osf_stat; + +static void linux_to_osf_statfs (struct statfs * linux_stat, struct osf_statfs * osf_stat) +{ + osf_stat->f_type = linux_stat->f_type; + osf_stat->f_flags = 0; /* mount flags */ + /* Linux doesn't provide a "fundamental filesystem block size": */ + osf_stat->f_fsize = linux_stat->f_bsize; + osf_stat->f_bsize = linux_stat->f_bsize; + osf_stat->f_blocks = linux_stat->f_blocks; + osf_stat->f_bfree = linux_stat->f_bfree; + osf_stat->f_bavail = linux_stat->f_bavail; + osf_stat->f_files = linux_stat->f_files; + osf_stat->f_ffree = linux_stat->f_ffree; + osf_stat->f_fsid = linux_stat->f_fsid; +} + + +asmlinkage int osf_statfs(char * path, struct osf_statfs * buffer, unsigned long bufsiz) { + struct statfs linux_stat; struct inode * inode; int retval; - if (bufsiz > sizeof(struct statfs)) - bufsiz = sizeof(struct statfs); + if (bufsiz > sizeof(struct osf_statfs)) + bufsiz = sizeof(struct osf_statfs); retval = verify_area(VERIFY_WRITE, buffer, bufsiz); if (retval) return retval; @@ -197,13 +241,15 @@ iput(inode); return -ENOSYS; } - inode->i_sb->s_op->statfs(inode->i_sb, buffer, bufsiz); + inode->i_sb->s_op->statfs(inode->i_sb, &linux_stat, sizeof(linux_stat)); + linux_to_osf_statfs(&linux_stat, buffer); iput(inode); return 0; } -asmlinkage int osf_fstatfs(unsigned long fd, struct statfs * buffer, unsigned long bufsiz) +asmlinkage int osf_fstatfs(unsigned long fd, struct osf_statfs * buffer, unsigned long bufsiz) { + struct statfs linux_stat; struct file * file; struct inode * inode; int retval; @@ -211,15 +257,16 @@ retval = verify_area(VERIFY_WRITE, buffer, bufsiz); if (retval) return retval; - if (bufsiz > sizeof(struct statfs)) - bufsiz = sizeof(struct statfs); + if (bufsiz > sizeof(struct osf_statfs)) + bufsiz = sizeof(struct osf_statfs); if (fd >= NR_OPEN || !(file = current->files->fd[fd])) return -EBADF; if (!(inode = file->f_inode)) return -ENOENT; if (!inode->i_sb->s_op->statfs) return -ENOSYS; - inode->i_sb->s_op->statfs(inode->i_sb, buffer, bufsiz); + inode->i_sb->s_op->statfs(inode->i_sb, &linux_stat, sizeof(linux_stat)); + linux_to_osf_statfs(&linux_stat, buffer); return 0; } diff -ur --new-file old/linux/arch/alpha/kernel/process.c new/linux/arch/alpha/kernel/process.c --- old/linux/arch/alpha/kernel/process.c Wed Feb 28 11:00:49 1996 +++ new/linux/arch/alpha/kernel/process.c Sun Aug 18 09:37:57 1996 @@ -8,6 +8,7 @@ * This file handles the architecture-dependent parts of process handling.. */ +#include #include #include #include @@ -24,6 +25,7 @@ #include #include #include +#include #include #include @@ -52,6 +54,11 @@ void hard_reset_now(void) { +#if defined(CONFIG_ALPHA_SRM) && defined(CONFIG_ALPHA_ALCOR) + /* who said DEC engineer's have no sense of humor? ;-)) */ + *(int *) GRU_RESET = 0x0000dead; + mb(); +#endif halt(); } @@ -74,6 +81,17 @@ } /* + * Re-start a thread when doing execve() + */ +void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) +{ + set_fs(USER_DS); + regs->pc = pc; + regs->ps = 8; + wrusp(sp); +} + +/* * Free current thread data structures etc.. */ void exit_thread(void) @@ -139,7 +157,8 @@ childstack->r26 = (unsigned long) ret_from_sys_call; p->tss.usp = usp; p->tss.ksp = (unsigned long) childstack; - p->tss.flags = 1; + p->tss.pal_flags = 1; /* set FEN, clear everything else */ + p->tss.flags = current->tss.flags; p->mm->context = 0; } @@ -199,6 +218,14 @@ dump->regs[EF_A1] = pt->r17; dump->regs[EF_A2] = pt->r18; memcpy((char *)dump->regs + EF_SIZE, sw->fp, 32 * 8); +} + +int dump_fpu (struct pt_regs * regs, elf_fpregset_t *r) +{ + /* switch stack follows right below pt_regs: */ + struct switch_stack * sw = ((struct switch_stack *) regs) - 1; + memcpy(r, sw->fp, 32 * 8); + return 1; } /* diff -ur --new-file old/linux/arch/alpha/kernel/setup.c new/linux/arch/alpha/kernel/setup.c --- old/linux/arch/alpha/kernel/setup.c Tue Jun 4 05:06:37 1996 +++ new/linux/arch/alpha/kernel/setup.c Sun Aug 18 09:37:57 1996 @@ -135,11 +135,10 @@ * installation. Later we'll add other abbreviations * as well... */ - if(strcmp(COMMAND_LINE, "INSTALL") == 0) { + if (strcmp(COMMAND_LINE, "INSTALL") == 0) { strcpy(command_line, "root=/dev/fd0 load_ramdisk=1"); strcpy(saved_command_line, command_line); - } - else { + } else { strcpy(command_line, COMMAND_LINE); strcpy(saved_command_line, COMMAND_LINE); } diff -ur --new-file old/linux/arch/alpha/kernel/signal.c new/linux/arch/alpha/kernel/signal.c --- old/linux/arch/alpha/kernel/signal.c Thu Apr 18 13:00:23 1996 +++ new/linux/arch/alpha/kernel/signal.c Tue Aug 20 12:41:32 1996 @@ -30,24 +30,42 @@ /* * The OSF/1 sigprocmask calling sequence is different from the * C sigprocmask() sequence.. + * + * how: + * 1 - SIG_BLOCK + * 2 - SIG_UNBLOCK + * 3 - SIG_SETMASK + * + * We change the range to -1 .. 1 in order to let gcc easily + * use the conditional move instructions. */ -asmlinkage unsigned long osf_sigprocmask(int how, unsigned long newmask) +asmlinkage unsigned long osf_sigprocmask(int how, unsigned long newmask, + long a2, long a3, long a4, long a5, struct pt_regs regs) { - unsigned long oldmask = current->blocked; + unsigned long ok, oldmask; + struct task_struct * tsk; - newmask &= _BLOCKABLE; - switch (how) { - case SIG_BLOCK: - current->blocked |= newmask; - return oldmask; - case SIG_UNBLOCK: - current->blocked &= ~newmask; - return oldmask; - case SIG_SETMASK: - current->blocked = newmask; - return oldmask; + ok = how-1; /* 0 .. 2 */ + tsk = current; + ok = ok <= 2; + oldmask = -EINVAL; + if (ok) { + long sign; /* -1 .. 1 */ + unsigned long block, unblock; + + oldmask = tsk->blocked; + newmask &= _BLOCKABLE; + sign = how-2; + unblock = oldmask & ~newmask; + block = oldmask | newmask; + if (!sign) + block = unblock; + regs.r0 = 0; /* special no error return */ + if (sign <= 0) + newmask = block; + tsk->blocked = newmask; } - return -EINVAL; + return oldmask; } /* @@ -130,24 +148,28 @@ /* * Set up a signal frame... */ -static void setup_frame(struct sigaction * sa, struct sigcontext_struct ** fp, - unsigned long pc, struct pt_regs * regs, +static void setup_frame(struct sigaction * sa, + struct pt_regs * regs, struct switch_stack * sw, int signr, unsigned long oldmask) { int i; + unsigned long oldsp; struct sigcontext_struct * sc; - sc = *fp; + oldsp = rdusp(); + sc = ((struct sigcontext_struct *) oldsp) - 1; + /* check here if we would need to switch stacks.. */ - sc--; if (verify_area(VERIFY_WRITE, sc, sizeof(*sc))) do_exit(SIGSEGV); + wrusp((unsigned long) sc); + put_fs_quad(oldmask, &sc->sc_mask); put_fs_quad(8, &sc->sc_ps); - put_fs_quad(pc, &sc->sc_pc); - put_fs_quad((unsigned long)*fp, sc->sc_regs+30); + put_fs_quad(regs->pc, &sc->sc_pc); + put_fs_quad(oldsp, sc->sc_regs+30); put_fs_quad(regs->r0 , sc->sc_regs+0); put_fs_quad(regs->r1 , sc->sc_regs+1); @@ -193,14 +215,51 @@ */ put_fs_quad(0x43ecf40047de0410, sc->sc_retcode+0); put_fs_quad(0x0000000000000083, sc->sc_retcode+1); + imb(); + + /* "return" to the handler */ + regs->r27 = regs->pc = (unsigned long) sa->sa_handler; regs->r26 = (unsigned long) sc->sc_retcode; regs->r16 = signr; /* a0: signal number */ regs->r17 = 0; /* a1: exception code; see gentrap.h */ regs->r18 = (unsigned long) sc; /* a2: sigcontext pointer */ - *fp = sc; } /* + * OK, we're invoking a handler + */ +static inline void handle_signal(unsigned long signr, struct sigaction *sa, + unsigned long oldmask, struct pt_regs * regs, struct switch_stack *sw) +{ + setup_frame(sa,regs,sw,signr,oldmask); + + if (sa->sa_flags & SA_ONESHOT) + sa->sa_handler = NULL; + if (!(sa->sa_flags & SA_NOMASK)) + current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE; +} + +static inline void syscall_restart(unsigned long r0, unsigned long r19, + struct pt_regs * regs, struct sigaction * sa) +{ + switch (regs->r0) { + case ERESTARTNOHAND: + no_system_call_restart: + regs->r0 = EINTR; + break; + case ERESTARTSYS: + if (!(sa->sa_flags & SA_RESTART)) + goto no_system_call_restart; + /* fallthrough */ + case ERESTARTNOINTR: + regs->r0 = r0; /* reset v0 and a3 and replay syscall */ + regs->r19 = r19; + regs->pc -= 4; + } +} + + +/* * Note that 'init' is a special process: it doesn't get signals it doesn't * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. @@ -219,9 +278,6 @@ unsigned long r0, unsigned long r19) { unsigned long mask = ~current->blocked; - unsigned long handler_signal = 0; - struct sigcontext_struct *frame = NULL; - unsigned long pc = 0; unsigned long signr, single_stepping; struct sigaction * sa; @@ -264,7 +320,10 @@ case SIGCONT: case SIGCHLD: case SIGWINCH: continue; - case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU: + case SIGTSTP: case SIGTTIN: case SIGTTOU: + if (is_orphaned_pgrp(current->pgrp)) + continue; + case SIGSTOP: if (current->flags & PF_PTRACED) continue; current->state = TASK_STOPPED; @@ -289,16 +348,13 @@ do_exit(signr); } } - /* - * OK, we're invoking a handler - */ - if (r0) { - if (regs->r0 == ERESTARTNOHAND || - (regs->r0 == ERESTARTSYS && !(sa->sa_flags & SA_RESTART))) - regs->r0 = EINTR; + if (r0) + syscall_restart(r0, r19, regs, sa); + handle_signal(signr, sa, oldmask, regs, sw); + if (single_stepping) { + ptrace_set_bpt(current); /* re-set breakpoint */ } - handler_signal |= 1 << (signr-1); - mask &= ~sa->sa_mask; + return 1; } if (r0 && (regs->r0 == ERESTARTNOHAND || @@ -308,34 +364,8 @@ regs->r19 = r19; regs->pc -= 4; } - if (!handler_signal) { /* no handler will be called - return 0 */ - if (single_stepping) { - ptrace_set_bpt(current); /* re-set breakpoint */ - } - return 0; - } - pc = regs->pc; - frame = (struct sigcontext_struct *) rdusp(); - signr = 1; - sa = current->sig->action; - for (mask = 1 ; mask ; sa++,signr++,mask += mask) { - if (mask > handler_signal) - break; - if (!(mask & handler_signal)) - continue; - setup_frame(sa,&frame,pc,regs,sw,signr,oldmask); - pc = (unsigned long) sa->sa_handler; - regs->r27 = pc; - if (sa->sa_flags & SA_ONESHOT) - sa->sa_handler = NULL; - current->blocked |= sa->sa_mask; - oldmask |= sa->sa_mask; - } - imb(); - wrusp((unsigned long) frame); - regs->pc = pc; /* "return" to the first handler */ if (single_stepping) { ptrace_set_bpt(current); /* re-set breakpoint */ } - return 1; + return 0; } diff -ur --new-file old/linux/arch/alpha/lib/Makefile new/linux/arch/alpha/lib/Makefile --- old/linux/arch/alpha/lib/Makefile Wed Apr 24 11:57:53 1996 +++ new/linux/arch/alpha/lib/Makefile Fri Jul 12 11:29:45 1996 @@ -3,7 +3,7 @@ # OBJS = __divqu.o __remqu.o __divlu.o __remlu.o memset.o memcpy.o io.o \ - checksum.o strlen.o + checksum.o csum_partial_copy.o strlen.o lib.a: $(OBJS) $(AR) rcs lib.a $(OBJS) diff -ur --new-file old/linux/arch/alpha/lib/checksum.c new/linux/arch/alpha/lib/checksum.c --- old/linux/arch/alpha/lib/checksum.c Mon Jul 10 15:59:58 1995 +++ new/linux/arch/alpha/lib/checksum.c Wed Jul 17 13:38:43 1996 @@ -139,28 +139,6 @@ } /* - * the same as csum_partial, but copies from src while it - * checksums - * - * here even more important to align src and dst on a 32-bit (or even - * better 64-bit) boundary - */ - -unsigned int csum_partial_copy(char *src, char *dst, int len, int sum) -{ - /* - * The whole idea is to do the copy and the checksum at - * the same time, but we do it the easy way now. - * - * At least csum on the source, not destination, for cache - * reasons.. - */ - sum = csum_partial(src, len, sum); - memcpy(dst, src, len); - return sum; -} - -/* * this routine is used for miscellaneous IP-like checksums, mainly * in icmp.c */ diff -ur --new-file old/linux/arch/alpha/lib/csum_partial_copy.c new/linux/arch/alpha/lib/csum_partial_copy.c --- old/linux/arch/alpha/lib/csum_partial_copy.c Thu Jan 1 01:00:00 1970 +++ new/linux/arch/alpha/lib/csum_partial_copy.c Wed Jul 17 13:39:21 1996 @@ -0,0 +1,300 @@ +/* + * csum_partial_copy - do IP checksumming and copy + * + * (C) Copyright 1996 Linus Torvalds + * + * Don't look at this too closely - you'll go mad. The things + * we do for performance.. + */ + +#define ldq_u(x,y) \ +__asm__ __volatile__("ldq_u %0,%1":"=r" (x):"m" (*(unsigned long *)(y))) + +#define stq_u(x,y) \ +__asm__ __volatile__("stq_u %1,%0":"=m" (*(unsigned long *)(y)):"r" (x)) + +#define extql(x,y,z) \ +__asm__ __volatile__("extql %1,%2,%0":"=r" (z):"r" (x),"r" (y)) + +#define extqh(x,y,z) \ +__asm__ __volatile__("extqh %1,%2,%0":"=r" (z):"r" (x),"r" (y)) + +#define mskql(x,y,z) \ +__asm__ __volatile__("mskql %1,%2,%0":"=r" (z):"r" (x),"r" (y)) + +#define mskqh(x,y,z) \ +__asm__ __volatile__("mskqh %1,%2,%0":"=r" (z):"r" (x),"r" (y)) + +#define insql(x,y,z) \ +__asm__ __volatile__("insql %1,%2,%0":"=r" (z):"r" (x),"r" (y)) + +#define insqh(x,y,z) \ +__asm__ __volatile__("insqh %1,%2,%0":"=r" (z):"r" (x),"r" (y)) + +/* + * Ok. This isn't fun, but this is the EASY case. + */ +static inline unsigned long csum_partial_copy_aligned( + unsigned long *src, unsigned long *dst, + long len, unsigned long checksum) +{ + unsigned long carry = 0; + + while (len >= 0) { + unsigned long word = *src; + checksum += carry; + src++; + checksum += word; + len -= 8; + carry = checksum < word; + *dst = word; + dst++; + } + len += 8; + checksum += carry; + if (len) { + unsigned long word, tmp; + word = *src; + tmp = *dst; + mskql(word, len, word); + checksum += word; + mskqh(tmp, len, tmp); + carry = checksum < word; + *dst = word | tmp; + checksum += carry; + } + return checksum; +} + +/* + * This is even less fun, but this is still reasonably + * easy. + */ +static inline unsigned long csum_partial_copy_dest_aligned( + unsigned long *src, unsigned long *dst, + unsigned long soff, + long len, unsigned long checksum) +{ + unsigned long first; + unsigned long word, carry; + unsigned long lastsrc = 7+len+(unsigned long)src; + + ldq_u(first,src); + carry = 0; + while (len >= 0) { + unsigned long second; + + ldq_u(second, src+1); + extql(first, soff, word); + len -= 8; + src++; + extqh(second, soff, first); + checksum += carry; + word |= first; + first = second; + checksum += word; + *dst = word; + dst++; + carry = checksum < word; + } + len += 8; + checksum += carry; + if (len) { + unsigned long tmp; + unsigned long second; + ldq_u(second, lastsrc); + tmp = *dst; + extql(first, soff, word); + extqh(second, soff, first); + word |= first; + mskql(word, len, word); + checksum += word; + mskqh(tmp, len, tmp); + carry = checksum < word; + *dst = word | tmp; + checksum += carry; + } + return checksum; +} + +/* + * This is slightly less fun than the above.. + */ +static inline unsigned long csum_partial_copy_src_aligned( + unsigned long *src, unsigned long *dst, + unsigned long doff, + long len, unsigned long checksum, + unsigned long partial_dest) +{ + unsigned long carry = 0; + unsigned long word; + + mskql(partial_dest, doff, partial_dest); + while (len >= 0) { + unsigned long second_dest; + word = *src; + len -= 8; + insql(word, doff, second_dest); + checksum += carry; + stq_u(partial_dest | second_dest, dst); + src++; + checksum += word; + insqh(word, doff, partial_dest); + carry = checksum < word; + dst++; + } + len += doff; + checksum += carry; + if (len >= 0) { + unsigned long second_dest; + word = *src; + mskql(word, len-doff, word); + checksum += word; + insql(word, doff, second_dest); + stq_u(partial_dest | second_dest, dst); + carry = checksum < word; + if (len) { + ldq_u(second_dest, dst+1); + insqh(word, doff, partial_dest); + mskqh(second_dest, len, second_dest); + stq_u(partial_dest | second_dest, dst+1); + } + checksum += carry; + } else if (len & 7) { + unsigned long second_dest; + word = *src; + ldq_u(second_dest, dst); + mskql(word, len-doff, word); + checksum += word; + mskqh(second_dest, len, second_dest); + carry = checksum < word; + insql(word, doff, word); + stq_u(partial_dest | word | second_dest, dst); + checksum += carry; + } + return checksum; +} + +/* + * This is so totally un-fun that it's frightening. Don't + * look at this too closely, you'll go blind. + */ +static inline unsigned long csum_partial_copy_unaligned( + unsigned long * src, unsigned long * dst, + unsigned long soff, unsigned long doff, + long len, unsigned long checksum, + unsigned long partial_dest) +{ + unsigned long carry = 0; + unsigned long first; + unsigned long lastsrc; + + ldq_u(first, src); + lastsrc = 7+len+(unsigned long)src; + mskql(partial_dest, doff, partial_dest); + while (len >= 0) { + unsigned long second, word; + unsigned long second_dest; + + ldq_u(second, src+1); + extql(first, soff, word); + checksum += carry; + len -= 8; + extqh(second, soff, first); + src++; + word |= first; + first = second; + insql(word, doff, second_dest); + checksum += word; + stq_u(partial_dest | second_dest, dst); + carry = checksum < word; + insqh(word, doff, partial_dest); + dst++; + } + len += doff; + checksum += carry; + if (len >= 0) { + unsigned long second, word; + unsigned long second_dest; + + ldq_u(second, lastsrc); + extql(first, soff, word); + extqh(second, soff, first); + word |= first; + first = second; + mskql(word, len-doff, word); + checksum += word; + insql(word, doff, second_dest); + carry = checksum < word; + stq_u(partial_dest | second_dest, dst); + if (len) { + ldq_u(second_dest, dst+1); + insqh(word, doff, partial_dest); + mskqh(second_dest, len, second_dest); + stq_u(partial_dest | second_dest, dst+1); + } + checksum += carry; + } else if (len & 7) { + unsigned long second, word; + unsigned long second_dest; + + ldq_u(second, lastsrc); + extql(first, soff, word); + extqh(second, soff, first); + word |= first; + ldq_u(second_dest, dst); + mskql(word, len-doff, word); + checksum += word; + mskqh(second_dest, len, second_dest); + carry = checksum < word; + insql(word, doff, word); + stq_u(partial_dest | word | second_dest, dst); + checksum += carry; + } + return checksum; +} + +unsigned int csum_partial_copy(char *src, char *dst, int len, int sum) +{ + unsigned long checksum = (unsigned) sum; + unsigned long soff = 7 & (unsigned long) src; + unsigned long doff = 7 & (unsigned long) dst; + + if (len) { + if (!doff) { + if (!soff) + checksum = csum_partial_copy_aligned( + (unsigned long *) src, + (unsigned long *) dst, + len-8, checksum); + else + checksum = csum_partial_copy_dest_aligned( + (unsigned long *) src, + (unsigned long *) dst, + soff, len-8, checksum); + } else { + unsigned long partial_dest; + ldq_u(partial_dest, dst); + if (!soff) + checksum = csum_partial_copy_src_aligned( + (unsigned long *) src, + (unsigned long *) dst, + doff, len-8, checksum, + partial_dest); + else + checksum = csum_partial_copy_unaligned( + (unsigned long *) src, + (unsigned long *) dst, + soff, doff, len-8, checksum, + partial_dest); + } + /* 64 -> 33 bits */ + checksum = (checksum & 0xffffffff) + (checksum >> 32); + /* 33 -> < 32 bits */ + checksum = (checksum & 0xffff) + (checksum >> 16); + /* 32 -> 16 bits */ + checksum = (checksum & 0xffff) + (checksum >> 16); + checksum = (checksum & 0xffff) + (checksum >> 16); + } + return checksum; +} diff -ur --new-file old/linux/arch/alpha/lib/io.c new/linux/arch/alpha/lib/io.c --- old/linux/arch/alpha/lib/io.c Thu Nov 9 09:04:33 1995 +++ new/linux/arch/alpha/lib/io.c Tue Aug 20 15:57:15 1996 @@ -156,24 +156,83 @@ /* * Read COUNT 32-bit words from port PORT into memory starting at - * SRC. SRC must be at least word aligned. This is used by the - * IDE driver to read disk sectors. Performance is important, but - * the interfaces seems to be slow: just using the inlined version - * of the inw() breaks things. + * SRC. Now works with any alignment in SRC. Performance is important, + * but the interfaces seems to be slow: just using the inlined version + * of the inl() breaks things. */ void insl (unsigned long port, void *dst, unsigned long count) { - if (((unsigned long)dst) & 0x3) { - panic("insl: memory not aligned"); - } - - while (count) { + unsigned int l = 0, l2; + + if (!count) + return; + + switch (((unsigned long) dst) & 0x3) + { + case 0x00: /* Buffer 32-bit aligned */ + while (count--) + { + *(unsigned int *) dst = inl(port); + ((unsigned int *) dst)++; + } + break; + + /* Assuming little endian Alphas in cases 0x01 -- 0x03 ... */ + + case 0x02: /* Buffer 16-bit aligned */ + --count; + + l = inl(port); + *(unsigned short *) dst = l; + ((unsigned short *) dst)++; + + while (count--) + { + l2 = inl(port); + *(unsigned int *) dst = l >> 16 | l2 << 16; + ((unsigned int *) dst)++; + l = l2; + } + *(unsigned short *) dst = l >> 16; + break; + case 0x01: /* Buffer 8-bit aligned */ + --count; + + l = inl(port); + *(unsigned char *) dst = l; + ((unsigned char *) dst)++; + *(unsigned short *) dst = l >> 8; + ((unsigned short *) dst)++; + while (count--) + { + l2 = inl(port); + *(unsigned int *) dst = l >> 24 | l2 << 8; + ((unsigned int *) dst)++; + l = l2; + } + *(unsigned char *) dst = l >> 24; + break; + case 0x03: /* Buffer 8-bit aligned */ --count; - *(unsigned int *) dst = inl(port); - ((unsigned int *) dst)++; + + l = inl(port); + *(unsigned char *) dst = l; + ((unsigned char *) dst)++; + while (count--) + { + l2 = inl(port); + *(unsigned int *) dst = l << 24 | l2 >> 8; + ((unsigned int *) dst)++; + l = l2; + } + *(unsigned short *) dst = l >> 8; + ((unsigned short *) dst)++; + *(unsigned char *) dst = l >> 24; + break; } } + /* * Like insb but in the opposite direction. * Don't worry as much about doing aligned memory transfers: @@ -223,20 +282,79 @@ /* * Like insl but in the opposite direction. This is used by the IDE - * driver to write disk sectors. Performance is important, but the - * interfaces seems to be slow: just using the inlined version of the - * outw() breaks things. + * driver to write disk sectors. Works with any alignment in SRC. + * Performance is important, but the interfaces seems to be slow: + * just using the inlined version of the outl() breaks things. */ void outsl (unsigned long port, const void *src, unsigned long count) { - if (((unsigned long)src) & 0x3) { - panic("outsw: memory not aligned"); - } - - while (count) { + unsigned int l = 0, l2; + + if (!count) + return; + + switch (((unsigned long) src) & 0x3) + { + case 0x00: /* Buffer 32-bit aligned */ + while (count--) + { + outl(*(unsigned int *) src, port); + ((unsigned int *) src)++; + } + break; + + /* Assuming little endian Alphas in cases 0x01 -- 0x03 ... */ + + case 0x02: /* Buffer 16-bit aligned */ --count; - outl(*(unsigned int *) src, port); - ((unsigned int *) src)++; + + l = *(unsigned short *) src << 16; + ((unsigned short *) src)++; + + while (count--) + { + l2 = *(unsigned int *) src; + ((unsigned int *) src)++; + outl (l >> 16 | l2 << 16, port); + l = l2; + } + l2 = *(unsigned short *) src; + outl (l >> 16 | l2 << 16, port); + break; + case 0x01: /* Buffer 8-bit aligned */ + --count; + + l = *(unsigned char *) src << 8; + ((unsigned char *) src)++; + l |= *(unsigned short *) src << 16; + ((unsigned short *) src)++; + while (count--) + { + l2 = *(unsigned int *) src; + ((unsigned int *) src)++; + outl (l >> 8 | l2 << 24, port); + l = l2; + } + l2 = *(unsigned char *) src; + outl (l >> 8 | l2 << 24, port); + break; + case 0x03: /* Buffer 8-bit aligned */ + --count; + + l = *(unsigned char *) src << 24; + ((unsigned char *) src)++; + while (count--) + { + l2 = *(unsigned int *) src; + ((unsigned int *) src)++; + outl (l >> 24 | l2 << 8, port); + l = l2; + } + l2 = *(unsigned short *) src; + ((unsigned short *) src)++; + l2 |= *(unsigned char *) src << 16; + outl (l >> 24 | l2 << 8, port); + break; } } diff -ur --new-file old/linux/arch/alpha/lib/memcpy.c new/linux/arch/alpha/lib/memcpy.c --- old/linux/arch/alpha/lib/memcpy.c Fri Dec 22 07:22:05 1995 +++ new/linux/arch/alpha/lib/memcpy.c Sun Aug 4 12:37:59 1996 @@ -128,4 +128,8 @@ * gcc-2.7.1 and newer generate calls to memset and memcpy. So we * need to define that here: */ -asm (".weakext memcpy, __memcpy"); +#ifdef __ELF__ + asm (".weak memcpy; memcpy = __memcpy"); +#else + asm (".weakext memcpy, __memcpy"); +#endif diff -ur --new-file old/linux/arch/alpha/lib/memset.S new/linux/arch/alpha/lib/memset.S --- old/linux/arch/alpha/lib/memset.S Tue Apr 23 19:49:01 1996 +++ new/linux/arch/alpha/lib/memset.S Sun Aug 4 12:37:59 1996 @@ -103,4 +103,8 @@ ret $31,($26),1 /* E1 */ .end __memset -.weakext memset, __memset +#ifdef __ELF__ + .weak memset; memset = __memset +#else + .weakext memset, __memset +#endif diff -ur --new-file old/linux/arch/alpha/mm/fault.c new/linux/arch/alpha/mm/fault.c --- old/linux/arch/alpha/mm/fault.c Thu Apr 25 07:43:43 1996 +++ new/linux/arch/alpha/mm/fault.c Sat Jul 27 08:49:05 1996 @@ -84,7 +84,6 @@ if (!(vma->vm_flags & VM_WRITE)) goto bad_area; } - tbis(address); handle_mm_fault(vma, address, cause > 0); return; diff -ur --new-file old/linux/arch/alpha/mm/init.c new/linux/arch/alpha/mm/init.c --- old/linux/arch/alpha/mm/init.c Sun Apr 14 10:43:56 1996 +++ new/linux/arch/alpha/mm/init.c Sun Aug 18 09:37:57 1996 @@ -131,7 +131,8 @@ newptbr = ((unsigned long) swapper_pg_dir - PAGE_OFFSET) >> PAGE_SHIFT; pgd_val(swapper_pg_dir[1023]) = (newptbr << 32) | pgprot_val(PAGE_KERNEL); init_task.tss.ptbr = newptbr; - init_task.tss.flags = 1; + init_task.tss.pal_flags = 1; /* set FEN, clear everything else */ + init_task.tss.flags = 0; init_task.kernel_stack_page = INIT_STACK; load_PCB(&init_task.tss); diff -ur --new-file old/linux/arch/i386/Makefile new/linux/arch/i386/Makefile --- old/linux/arch/i386/Makefile Sat Mar 9 12:31:42 1996 +++ new/linux/arch/i386/Makefile Thu Jul 25 18:35:00 1996 @@ -37,9 +37,10 @@ LD=$(CROSS_COMPILE)ld -m elf_i386 CPP=$(CC) -E -D__ELF__ -OBJDUMP =$(CROSS_COMPILE)objdump -ENCAPS=$(CROSS_COMPILE)encaps +OBJDUMP=$(CROSS_COMPILE)objdump OBJDUMP_FLAGS=-k -q +ENCAPS=$(CROSS_COMPILE)encaps +OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -R .stab -R .stabstr ZLDFLAGS=-e startup_32 LDFLAGS=-e stext ZIMAGE_OFFSET=0x1000 diff -ur --new-file old/linux/arch/i386/boot/Makefile new/linux/arch/i386/boot/Makefile --- old/linux/arch/i386/boot/Makefile Sun May 5 08:05:58 1996 +++ new/linux/arch/i386/boot/Makefile Wed Jul 17 13:59:14 1996 @@ -18,7 +18,11 @@ zImage: $(CONFIGURE) bootsect setup compressed/vmlinux tools/build ifdef CONFIG_KERNEL_ELF - $(OBJDUMP) $(OBJDUMP_FLAGS) -o $(ZIMAGE_OFFSET) compressed/vmlinux > compressed/vmlinux.out + if hash $(ENCAPS) 2> /dev/null; then \ + $(OBJDUMP) $(OBJDUMP_FLAGS) -o $(ZIMAGE_OFFSET) compressed/vmlinux > compressed/vmlinux.out; \ + else \ + $(OBJCOPY) compressed/vmlinux compressed/vmlinux.out; \ + fi tools/build bootsect setup compressed/vmlinux.out $(ROOT_DEV) > zImage else tools/build bootsect setup compressed/vmlinux $(ROOT_DEV) > zImage @@ -27,7 +31,11 @@ bzImage: $(CONFIGURE) bbootsect setup compressed/bvmlinux tools/bbuild ifdef CONFIG_KERNEL_ELF - $(OBJDUMP) $(OBJDUMP_FLAGS) -o $(IMAGE_OFFSET) compressed/bvmlinux > compressed/bvmlinux.out + if hash $(ENCAPS) 2> /dev/null; then \ + $(OBJDUMP) $(OBJDUMP_FLAGS) -o $(IMAGE_OFFSET) compressed/bvmlinux > compressed/bvmlinux.out; \ + else \ + $(OBJCOPY) compressed/bvmlinux compressed/bvmlinux.out; \ + fi tools/bbuild bbootsect setup compressed/bvmlinux.out $(ROOT_DEV) > bzImage else tools/bbuild bbootsect setup compressed/bvmlinux $(ROOT_DEV) > bzImage diff -ur --new-file old/linux/arch/i386/boot/compressed/Makefile new/linux/arch/i386/boot/compressed/Makefile --- old/linux/arch/i386/boot/compressed/Makefile Sat Mar 9 12:31:42 1996 +++ new/linux/arch/i386/boot/compressed/Makefile Wed Jul 17 13:59:14 1996 @@ -46,12 +46,21 @@ # You cannot compress a file and have the kernel uncompress it, it must # be stdin piggy.o: $(SYSTEM) - tmppiggy=/tmp/$$$$.piggy; \ - rm -f $$tmppiggy $$tmppiggy.gz; \ - $(OBJDUMP) $(OBJDUMP_FLAGS) -o $(IMAGE_OFFSET) $(SYSTEM) > $$tmppiggy; \ + tmppiggy=/tmp/$$$$piggy; \ + rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk; \ + if hash $(ENCAPS) 2> /dev/null; then \ + $(OBJDUMP) $(OBJDUMP_FLAGS) -o $(IMAGE_OFFSET) $(SYSTEM) > $$tmppiggy; \ + else \ + $(OBJCOPY) $(SYSTEM) $$tmppiggy; \ + fi; \ gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \ - $(ENCAPS) $(TARGET) piggy.o $$tmppiggy.gz $(INPUT_DATA) $(INPUT_LEN); \ - rm -f $$tmppiggy $$tmppiggy.gz + if hash $(ENCAPS) 2> /dev/null; then \ + $(ENCAPS) $(TARGET) piggy.o $$tmppiggy.gz $(INPUT_DATA) $(INPUT_LEN); \ + else \ + echo "SECTIONS { .data : { input_len = .; LONG(input_data_end - input_data) input_data = .; *(.data) input_data_end = .; }}" > $$tmppiggy.lnk; \ + ld -m elf_i386 -r -o piggy.o -b binary $$tmppiggy.gz -b elf32-i386 -T $$tmppiggy.lnk; \ + fi; \ + rm -f $$tmppiggy $$tmppiggy.gz $$tmppiggy.lnk else piggy.o: $(SYSTEM) xtract piggyback diff -ur --new-file old/linux/arch/i386/boot/compressed/misc.c new/linux/arch/i386/boot/compressed/misc.c --- old/linux/arch/i386/boot/compressed/misc.c Sat Mar 9 12:31:43 1996 +++ new/linux/arch/i386/boot/compressed/misc.c Mon Jul 15 12:47:39 1996 @@ -350,7 +350,7 @@ void setup_output_buffer_if_we_run_high(struct moveparams *mv) { high_buffer_start = (uch *)(((ulg)&end) + HEAP_SIZE); - if (EXT_MEM_K < (4*1024)) error("Less than 4MB of memory.\n"); + if (EXT_MEM_K < (3*1024)) error("Less than 4MB of memory.\n"); mv->low_buffer_start = output_data = (char *)LOW_BUFFER_START; high_loaded = 1; free_mem_end_ptr = (long)high_buffer_start; diff -ur --new-file old/linux/arch/i386/boot/tools/build.c new/linux/arch/i386/boot/tools/build.c --- old/linux/arch/i386/boot/tools/build.c Sat Mar 9 12:31:43 1996 +++ new/linux/arch/i386/boot/tools/build.c Wed Jul 10 12:10:59 1996 @@ -19,6 +19,7 @@ /* * Changes by tytso to allow root device specification * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996 + * Cross compiling fixes by Gertjan van Wingerde, July 1996 */ #include /* fprintf */ @@ -56,6 +57,7 @@ #define STRINGIFY(x) #x typedef union { + int i; long l; short s[2]; char b[4]; @@ -72,6 +74,17 @@ return t.l; } +int intel_int(int i) +{ + conv t; + + t.b[0] = i & 0xff; i >>= 8; + t.b[1] = i & 0xff; i >>= 8; + t.b[2] = i & 0xff; i >>= 8; + t.b[3] = i & 0xff; i >>= 8; + return t.i; +} + short intel_short(short l) { conv t; @@ -94,8 +107,8 @@ int main(int argc, char ** argv) { - int i,c,id, sz; - unsigned long sys_size; + int i,c,id,sz,tmp_int; + unsigned long sys_size, tmp_long; char buf[1024]; #ifndef __BFD__ struct exec *ex = (struct exec *)buf; @@ -180,12 +193,17 @@ #ifdef __BIG_KERNEL__ { if (!i) { - if (*((long *)(&buf[2])) != 0x53726448 ) + /* Working with memcpy because of alignment constraints + on Sparc - Gertjan */ + memcpy(&tmp_long, &buf[2], sizeof(long)); + if (tmp_long != intel_long(0x53726448) ) die("Wrong magic in loader header of 'setup'"); - if (*((int *)(&buf[6])) < 0x200 ) + memcpy(&tmp_int, &buf[6], sizeof(int)); + if (tmp_int < intel_int(0x200)) die("Wrong version of loader header of 'setup'"); buf[0x11] = 1; /* LOADED_HIGH */ - *((long *)(&buf[0x14])) = 0x100000; /* code32_start */ + tmp_long = intel_long(0x100000); + memcpy(&buf[0x14], &tmp_long, sizeof(long)); /* code32_start */ } #endif if (write(1,buf,c)!=c) diff -ur --new-file old/linux/arch/i386/defconfig new/linux/arch/i386/defconfig --- old/linux/arch/i386/defconfig Wed Jun 5 13:51:03 1996 +++ new/linux/arch/i386/defconfig Mon Aug 5 07:41:50 1996 @@ -44,8 +44,9 @@ # CONFIG_BLK_DEV_IDETAPE is not set # CONFIG_BLK_DEV_IDE_PCMCIA is not set CONFIG_BLK_DEV_CMD640=y -# CONFIG_BLK_DEV_TRITON is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set CONFIG_BLK_DEV_RZ1000=y +# CONFIG_BLK_DEV_TRITON is not set # CONFIG_IDE_CHIPSETS is not set # @@ -55,6 +56,7 @@ # CONFIG_BLK_DEV_MD is not set # CONFIG_BLK_DEV_RAM is not set # CONFIG_BLK_DEV_XD is not set +# CONFIG_BLK_DEV_HD is not set # # Networking options diff -ur --new-file old/linux/arch/i386/kernel/entry.S new/linux/arch/i386/kernel/entry.S --- old/linux/arch/i386/kernel/entry.S Mon May 13 22:23:08 1996 +++ new/linux/arch/i386/kernel/entry.S Wed Jul 17 11:33:25 1996 @@ -381,22 +381,21 @@ push %es push %ds pushl %eax + xorl %eax,%eax pushl %ebp pushl %edi pushl %esi pushl %edx + decl %eax # eax = -1 pushl %ecx pushl %ebx - movl $0,%eax - movl %eax,%db7 # disable hardware debugging... cld - movl $-1, %eax - xchgl %eax, ORIG_EAX(%esp) # orig_eax (get the error code. ) xorl %ebx,%ebx # zero ebx + xchgl %eax, ORIG_EAX(%esp) # orig_eax (get the error code. ) mov %gs,%bx # get the lower order bits of gs + movl %esp,%edx xchgl %ebx, GS(%esp) # get the address and save gs. pushl %eax # push the error code - lea 4(%esp),%edx pushl %edx movl $(KERNEL_DS),%edx mov %dx,%ds @@ -405,9 +404,6 @@ mov %dx,%fs #ifdef __SMP__ ENTER_KERNEL -#endif - pushl %eax -#ifdef __SMP__ GET_PROCESSOR_OFFSET(%eax) movl SYMBOL_NAME(current_set)(,%eax), %eax #else @@ -415,7 +411,6 @@ #endif movl %db6,%edx movl %edx,dbgreg6(%eax) # save current hardware debugging status - popl %eax call *%ebx addl $8,%esp jmp ret_from_sys_call diff -ur --new-file old/linux/arch/i386/kernel/ksyms.c new/linux/arch/i386/kernel/ksyms.c --- old/linux/arch/i386/kernel/ksyms.c Thu Feb 15 06:13:13 1996 +++ new/linux/arch/i386/kernel/ksyms.c Sat Jun 29 11:00:45 1996 @@ -14,6 +14,7 @@ #ifdef __SMP__ X(apic_reg), /* Needed internally for the I386 inlines */ X(cpu_data), + X(syscall_count), #endif #include }; diff -ur --new-file old/linux/arch/i386/kernel/process.c new/linux/arch/i386/kernel/process.c --- old/linux/arch/i386/kernel/process.c Fri Apr 19 17:35:15 1996 +++ new/linux/arch/i386/kernel/process.c Tue Aug 13 08:11:35 1996 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -206,6 +207,7 @@ for(j = 0; j < 100000 ; j++) /* nothing */; outb(0xfe,0x64); /* pulse reset low */ + udelay(10); } __asm__ __volatile__("\tlidt %0": "=m" (no_idt)); } @@ -332,7 +334,7 @@ /* * fill in the fpu structure for a core dump.. */ -int dump_fpu (struct user_i387_struct* fpu) +int dump_fpu (struct pt_regs * regs, struct user_i387_struct* fpu) { int fpvalid; @@ -377,7 +379,7 @@ dump->regs = *regs; - dump->u_fpvalid = dump_fpu (&dump->i387); + dump->u_fpvalid = dump_fpu (regs, &dump->i387); } asmlinkage int sys_fork(struct pt_regs regs) diff -ur --new-file old/linux/arch/i386/kernel/signal.c new/linux/arch/i386/kernel/signal.c --- old/linux/arch/i386/kernel/signal.c Mon May 6 15:31:18 1996 +++ new/linux/arch/i386/kernel/signal.c Tue Jul 2 18:08:34 1996 @@ -248,7 +248,8 @@ if (sa->sa_flags & SA_ONESHOT) sa->sa_handler = NULL; - current->blocked |= sa->sa_mask; + if (!(sa->sa_flags & SA_NOMASK)) + current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE; } /* @@ -310,7 +311,10 @@ case SIGCONT: case SIGCHLD: case SIGWINCH: continue; - case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU: + case SIGTSTP: case SIGTTIN: case SIGTTOU: + if (is_orphaned_pgrp(current->pgrp)) + continue; + case SIGSTOP: if (current->flags & PF_PTRACED) continue; current->state = TASK_STOPPED; diff -ur --new-file old/linux/arch/i386/kernel/time.c new/linux/arch/i386/kernel/time.c --- old/linux/arch/i386/kernel/time.c Sun Jun 2 11:37:09 1996 +++ new/linux/arch/i386/kernel/time.c Wed Aug 14 18:09:52 1996 @@ -68,7 +68,7 @@ */ if (test_bit(TIMER_BH, &bh_active) ) { - missing_time = 997670/HZ; + missing_time = 1000020/HZ; } /* Get last timer tick in absolute kernel time */ @@ -90,7 +90,7 @@ :"r" (tmp), "0" (eax), "1" (edx)); - edx = 997670/HZ; + edx = 1000020/HZ; tmp = eax; eax = 0; @@ -111,7 +111,7 @@ eax -= low_timer; /* - * Time offset = (997670/HZ * time_low) / quotient. + * Time offset = (1000020/HZ * time_low) / quotient. */ __asm__("mull %2" @@ -124,8 +124,8 @@ * we need to check the result so that we'll get a timer * that is monotonic. */ - if (edx >= 997670/HZ) - edx = 997670/HZ-1; + if (edx >= 1000020/HZ) + edx = 1000020/HZ-1; eax = edx + missing_time; return eax; diff -ur --new-file old/linux/arch/i386/kernel/traps.c new/linux/arch/i386/kernel/traps.c --- old/linux/arch/i386/kernel/traps.c Wed May 15 06:56:41 1996 +++ new/linux/arch/i386/kernel/traps.c Thu Aug 1 11:30:25 1996 @@ -173,8 +173,12 @@ DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS, current) DO_ERROR(11, SIGBUS, "segment not present", segment_not_present, current) DO_ERROR(12, SIGBUS, "stack segment", stack_segment, current) -DO_ERROR(15, SIGSEGV, "reserved", reserved, current) DO_ERROR(17, SIGSEGV, "alignment check", alignment_check, current) + +asmlinkage void do_reserved(struct pt_regs * regs, long error_code) +{ + printk("Uhhuh.. Reserved trap code, whazzup? (%ld)\n", error_code); +} asmlinkage void do_general_protection(struct pt_regs * regs, long error_code) { diff -ur --new-file old/linux/arch/m68k/atari/atafb.c new/linux/arch/m68k/atari/atafb.c --- old/linux/arch/m68k/atari/atafb.c Mon May 20 06:54:26 1996 +++ new/linux/arch/m68k/atari/atafb.c Mon Jul 15 08:55:11 1996 @@ -109,7 +109,7 @@ short xoffset; short hht, hbb, hbe, hdb, hde, hss; short vft, vbb, vbe, vdb, vde, vss; - /* auxiliary informations */ + /* auxiliary information */ short mono; short ste_mode; short bpp; diff -ur --new-file old/linux/arch/mips/kernel/Makefile new/linux/arch/mips/kernel/Makefile --- old/linux/arch/mips/kernel/Makefile Wed Dec 13 11:39:43 1995 +++ new/linux/arch/mips/kernel/Makefile Mon Jul 15 08:55:11 1996 @@ -63,11 +63,11 @@ endif ifdef CONFIG_CPU_R6000 - exit 1 # no detailed informations about CPU yet. + exit 1 # no detailed information about CPU yet. endif ifdef CONFIG_CPU_R8000 - exit 1 # no detailed informations about CPU yet. + exit 1 # no detailed information about CPU yet. endif ifdef CONFIG_CPU_R10000 diff -ur --new-file old/linux/arch/ppc/Makefile new/linux/arch/ppc/Makefile --- old/linux/arch/ppc/Makefile Mon May 27 11:00:57 1996 +++ new/linux/arch/ppc/Makefile Mon Jul 8 10:27:42 1996 @@ -15,58 +15,54 @@ # # PowerPC (cross) tools -AS = as.ppc -ASFLAGS = -LD = ld.ppc -#LINKFLAGS = -T arch/ppc/ld.script -Ttext 0x90000000 -Map vmlinux.map -LINKFLAGS = -T arch/ppc/ld.script -Ttext 0x90000000 +SUFFIX =.ppc +#AS = /u/cort/ppc/gcc/ppc-linux-elf/bin/as +AS = as$(SUFFIX) +ASFLAGS = +#LD = /u/cort/ppc/gcc/ppc-linux-elf/bin/ld +LD = ld$(SUFFIX) +LINKFLAGS = -T arch/ppc/ld.script -Ttext 0x90000000 HOSTCC = gcc -CC = cc.ppc -CFLAGS = -D__KERNEL__ -I$(TOPDIR)/include \ - -Wall -Wstrict-prototypes \ - -msoft-float \ +#CC = /u/cort/ppc/gcc/bin/gcc +CC = gcc$(SUFFIX) +#CC = /u/cort/ppc/gcc/bin/gcc.ppc +CFLAGS = -D__KERNEL__ -I$(TOPDIR)/include -D__powerpc__ \ + -Wstrict-prototypes \ -fomit-frame-pointer \ -fno-builtin \ -finhibit-size-directive \ - -fsigned-char \ - -O2 + -O2 -fsigned-char CPP = $(CC) -E $(CFLAGS) -AR = ar.ppc -RANLIB = ranlib.ppc -STRIP = strip.ppc -NM = nm.ppc +#AR = /u/cort/ppc/gcc/ppc-linux-elf/bin/ar +AR = ar$(SUFFIX) +#RANLIB = /u/cort/ppc/gcc/ppc-linux-elf/bin/ranlib +RANLIB = ar$(SUFFIX) +#STRIP = /u/cort/ppc/gcc/ppc-linux-elf/bin/strip +STRIP = strip$(SUFFIX) +#NM = /u/cort/ppc/gcc/ppc-linux-elf/bin/nm +NM = nm$(SUFFIX) # -# Set these to indicate how to link it.. +# NFS_ROOT_NAME specifies the default name of the directory to mount +# as root via NFS, if the kernel does not get the "root=" option from +# the boot loader. The "%s" will be replaced by the IP-number of the +# local system. # -# -zmagic: -# -# ZLINKFLAGS = -Ttext 0x1000 -# LINKFLAGS = -Ttext 0x100000 -# -# -qmagic (we need to remove the 32 byte header for bootup purposes) -# -## ZLINKFLAGS =-qmagic -Ttext 0xfe0 -## LINKFLAGS =-qmagic -Ttext 0xfffe0 -## CFLAGS := $(CFLAGS) -pipe - -## ifdef CONFIG_M486 -## CFLAGS := $(CFLAGS) -m486 -## else -## ifdef CONFIG_M586 -## CFLAGS := $(CFLAGS) -mpentium -## else -## CFLAGS := $(CFLAGS) -m386 -## endif -## endif +NFS_ROOT = -DNFS_ROOT="\"/joplin/ppc/root/\"" HEAD := arch/ppc/kernel/head.o ARCH_SUBDIRS = arch/ppc/kernel arch/ppc/mm arch/ppc/lib SUBDIRS := $(SUBDIRS) $(ARCH_SUBDIRS) ARCHIVES := arch/ppc/kernel/kernel.o arch/ppc/mm/mm.o arch/ppc/lib/lib.o $(ARCHIVES) -NO_RD_ARCHIVES := arch/ppc/kernel/no_ramdisk.o $(ARCHIVES) -ARCHIVES := arch/ppc/kernel/ramdisk.o $(ARCHIVES) + + +MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot + +tImage: vmlinux + @$(MAKEBOOT) tImage + + arch/ppc/kernel: dummy $(MAKE) linuxsubdirs SUBDIRS=arch/ppc/kernel @@ -77,41 +73,12 @@ arch/ppc/lib: dummy $(MAKE) linuxsubdirs SUBDIRS=arch/ppc/lib -MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot - -vmlinux.no_ramdisk: $(CONFIGURATION) init/main.o init/version.o linuxsubdirs - $(LD) $(LINKFLAGS) $(HEAD) init/main.o init/version.o \ - $(NO_RD_ARCHIVES) \ - $(FILESYSTEMS) \ - $(DRIVERS) \ - $(LIBS) -o vmlinux.no_ramdisk - -## -zImage: vmlinux - @$(MAKEBOOT) zImage - -tImage: vmlinux - @$(MAKEBOOT) tImage - -bImage: vmlinux.no_ramdisk - @$(MAKEBOOT) bImage - -bdisk: vmlinux.no_ramdisk - @$(MAKEBOOT) bdisk - -## compressed: zImage -## -## zlilo: vmlinux -## @$(MAKEBOOT) zlilo -## -zdisk: vmlinux - @$(MAKEBOOT) zdisk - -## install: vmlinux -## @$(MAKEBOOT) install archclean: - @$(MAKEBOOT) clean + /bin/rm -f arch/ppc/*/*.o #arch/ppc/kernel/mk_defs arch/ppc/kernel/ppc_defs.h + /bin/rm -f arch/ppc/*~ arch/ppc/*/*~ include/asm-ppc/*~ arch/ppc/boot/mkboot archdep: -# @$(MAKEBOOT) dep + +corttags : + etags arch/ppc/*/*.c include/asm-ppc/* drivers/*/*.c net/*.c */*.c diff -ur --new-file old/linux/arch/ppc/boot/Makefile new/linux/arch/ppc/boot/Makefile --- old/linux/arch/ppc/boot/Makefile Mon May 27 11:00:57 1996 +++ new/linux/arch/ppc/boot/Makefile Mon Jul 8 10:27:42 1996 @@ -22,50 +22,28 @@ OBJECTS = head.o main.o -all: linux.boot +all: linux.boot mkboot -#zImage: $(CONFIGURE) bootsect setup compressed/vmlinux tools/build -zImage: compressed/vmlinux mk_type41 - mkboot compressed/vmlinux vmlinux 0 - mk_type41 vmlinux zImage - cp compressed/vmlinux zBoot - rm -f vmlinux compressed/vmlinux +linux.boot: $(TOPDIR)/vmlinux mkboot + rsh charon /bin/rm -f /usr/tftpboot/vmlinux + /bin/rm -f /usr/tftpboot/vmlinux + ./mkboot $(TOPDIR)/vmlinux /usr/tftpboot/vmlinux + rcp /usr/tftpboot/vmlinux charon:/usr/tftpboot/vmlinux + sync -zdisk: zImage - dd if=zImage of=/dev/fd0 bs=36b - -compressed/vmlinux: $(TOPDIR)/vmlinux - @$(MAKE) -C compressed vmlinux - -tImage: mk_type41 $(TOPDIR)/vmlinux - mkboot $(TOPDIR)/vmlinux vmlinux 0 +tImage: mk_type41 $(TOPDIR)/vmlinux mkboot + ./mkboot $(TOPDIR)/vmlinux vmlinux mk_type41 vmlinux tImage - rm -f vmlinux + rm vmlinux -bImage: mk_type41 $(TOPDIR)/vmlinux.no_ramdisk - mkboot $(TOPDIR)/vmlinux.no_ramdisk vmlinux 0 - mk_type41 vmlinux bImage - rm -f vmlinux - -xImage: compressed/vmlinux.no_ramdisk - mkboot compressed/vmlinux.no_ramdisk vmlinux 0 - mk_type41 vmlinux xImage - rm -f vmlinux compressed/vmlinux.no_ramdisk - -compressed/vmlinux.no_ramdisk: $(TOPDIR)/vmlinux.no_ramdisk - @$(MAKE) -C compressed vmlinux.no_ramdisk - -bdisk: xImage - dd if=xImage of=/dev/fd0 bs=36b - -linux.boot: $(TOPDIR)/vmlinux - mkboot $(TOPDIR)/vmlinux $@ 0 +mkboot : cortstrip.c + $(HOSTCC) -o mkboot cortstrip.c mk_type41: mk_type41.c - cc -o mk_type41 mk_type41.c - + gcc -o mk_type41 mk_type41.c + clean: - rm -f linux.boot + rsh charon /bin/rm -f /usr/tftpboot/vmlinux + /bin/rm -f /usr/tftpboot/vmlinux dep: -fastdep: diff -ur --new-file old/linux/arch/ppc/boot/compressed/Makefile new/linux/arch/ppc/boot/compressed/Makefile --- old/linux/arch/ppc/boot/compressed/Makefile Mon May 27 11:00:57 1996 +++ new/linux/arch/ppc/boot/compressed/Makefile Mon Jul 8 10:27:42 1996 @@ -1,5 +1,5 @@ # -# linux/arch/i386/boot/compressed/Makefile +# linux/arch/ppc/boot/compressed/Makefile # # create a compressed vmlinux image from the original vmlinux # diff -ur --new-file old/linux/arch/ppc/boot/cortstrip.c new/linux/arch/ppc/boot/cortstrip.c --- old/linux/arch/ppc/boot/cortstrip.c Sat Dec 30 14:48:22 1995 +++ new/linux/arch/ppc/boot/cortstrip.c Mon Jul 8 10:27:42 1996 @@ -35,7 +35,7 @@ exit(-1); } - fdo = open(argv[2], O_WRONLY|O_CREAT); + fdo = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC,0755); if ( fdo == -1 ) { fprintf(stderr,"Couldn't open %s\n", argv[2]); diff -ur --new-file old/linux/arch/ppc/kernel/Makefile new/linux/arch/ppc/kernel/Makefile --- old/linux/arch/ppc/kernel/Makefile Mon May 27 11:00:57 1996 +++ new/linux/arch/ppc/kernel/Makefile Mon Jul 8 10:27:42 1996 @@ -25,10 +25,10 @@ HOST_CC = gcc OBJS = misc.o setup.o port_io.o irq.o pci.o traps.o stubs.o process.o \ - signal.o raw_printf.o ksyms.o time.o ramdisk_drvr.o syscalls.o \ - support.o ptrace.o + signal.o ksyms.o time.o syscalls.o \ + support.o ptrace.o # ramdisk_drvr.o -all: head.o kernel.o no_ramdisk.o ramdisk.o +all: head.o kernel.o #no_ramdisk.o ramdisk.o head.o: head.s head.s: head.S $(TOPDIR)/include/linux/tasks.h ppc_defs.h @@ -37,31 +37,31 @@ # simppc mk_defs -- $@ mk_defs $@ -no_ramdisk.o: no_ramdisk.S +#no_ramdisk.o: no_ramdisk.S + +#ramdisk.o: ramdisk.image mk_ramdisk +# mk_ramdisk ramdisk.image $*.s +# $(AS) -o $@ $*.s +# rm $*.s + +#mk_ramdisk: mk_ramdisk.c +# ${HOST_CC} -o mk_ramdisk mk_ramdisk.c -ramdisk.o: ramdisk.image mk_ramdisk - mk_ramdisk ramdisk.image $*.s - $(AS) -o $@ $*.s - rm $*.s - -mk_ramdisk: mk_ramdisk.c - ${HOST_CC} -o mk_ramdisk mk_ramdisk.c - mk_defs: mk_defs.c $(TOPDIR)/include/asm/mmu.h $(TOPDIR)/include/asm/processor.h $(TOPDIR)/include/asm/pgtable.h $(TOPDIR)/include/asm/ptrace.h # cc.ppc ${CFLAGS} -o mk_defs -T ld.script-user -Ttext 0x1000 mk_defs.c - cc.ppc ${CFLAGS} -o mk_defs mk_defs.c + gcc.ppc ${CFLAGS} -o mk_defs mk_defs.c kernel.o: $(OBJS) $(LD) -r -o kernel.o $(OBJS) sync -mkboot: mkboot.c - ${HOST_CC} -o $@ -Iinclude mkboot.c +#mkboot: mkboot.c +# ${HOST_CC} -o $@ -Iinclude mkboot.c dep: $(CPP) -M *.c > .depend - + fastdep: modules: diff -ur --new-file old/linux/arch/ppc/kernel/cortstrip.c new/linux/arch/ppc/kernel/cortstrip.c --- old/linux/arch/ppc/kernel/cortstrip.c Fri Oct 13 21:16:53 1995 +++ new/linux/arch/ppc/kernel/cortstrip.c Thu Jan 1 01:00:00 1970 @@ -1,62 +0,0 @@ -#include -#include -#include -#include - -/* amount to skip */ -/*#define PLACE 0x10000*/ - -/* size of read buffer */ -#define SIZE 0x10000 - -void main(int argc, char **argv ) -{ - int fd, fdo; - unsigned char data[SIZE]; - int i, n, skip; - - if ( argc != 4 ) - { - fprintf(stderr,"%s infile outfile skip\n", argv[0]); - exit(-1); - } - - - fd = open(argv[1], O_RDONLY); - if ( fd == -1 ) - { - fprintf(stderr,"Couldn't open %s\n", argv[1]); - perror("open()"); - exit(-1); - } - - fdo = open(argv[2], O_WRONLY|O_CREAT, 755); - if ( fdo == -1 ) - { - fprintf(stderr,"Couldn't open %s\n", argv[2]); - perror("open()"); - exit(-1); - } - - skip = atoi(argv[3]); - i = lseek(fd, skip, SEEK_SET); - printf("lseek'd %d bytes\n", i); - if ( i == -1 ) - { - perror("lseek()"); - } - - while ( (n = read(fd, data, SIZE)) > 0 ) - { - printf("Read %d bytes\n", n); - i = write(fdo, data, n); - printf("Wrote %d bytes\n", i); - } - - - close(fdo); - close(fd); - return(0); -} - - diff -ur --new-file old/linux/arch/ppc/kernel/head.S new/linux/arch/ppc/kernel/head.S --- old/linux/arch/ppc/kernel/head.S Mon May 27 11:00:57 1996 +++ new/linux/arch/ppc/kernel/head.S Mon Jul 8 10:27:42 1996 @@ -1,14 +1,14 @@ #include "ppc_asm.tmpl" #include "ppc_defs.h" #include - +#define NEWMM #define SYNC() \ isync; \ sync -/* #define TLB_STATS /* Trace TLB exceptions */ +/* #define TLB_STATS */ -/* Keep track of low-level exceptions - rather crude, but informative */ +/* Keep track of low-level exceptions - rather crude, but informative */ #define STATS /* @@ -50,9 +50,9 @@ /* gather some data without disturbing anything - Heisenberg are you watching? */ /* CAUTION! Don't turn on more than one of these at once! */ -/* #define DO_TRAP_TRACE /* */ -/* #define DO_TLB_TRACE /* */ -/* #define DO_RFI_TRACE /* */ +/* #define DO_TRAP_TRACE */ +/* #define DO_TLB_TRACE */ +/* #define DO_RFI_TRACE */ #ifdef DO_RFI_TRACE #define DO_RFI_TRACE_UNMAPPED(mark) \ @@ -801,8 +801,14 @@ lwz r0,4(r3) mtspr IBAT1L,r0 mtspr DBAT1L,r0 +/* this BAT mapping will cover all of kernel space */ +#ifdef NEWMM + lis r3,BAT2@h + ori r3,r3,BAT2@l +#else lis r3,TMP_BAT2@h ori r3,r3,TMP_BAT2@l +#endif andc r3,r3,r7 /* make unmapped address */ lwz r0,0(r3) mtspr IBAT2U,r0 @@ -847,7 +853,8 @@ DO_RFI_TRACE_MAPPED(0xDEAD0200) SYNC rfi -20: +20: + DO_RFI_TRACE_UNMAPPED(0xDEAD0400) 20: lis r3,BAT2@h ori r3,r3,BAT2@l diff -ur --new-file old/linux/arch/ppc/kernel/irq.c new/linux/arch/ppc/kernel/irq.c --- old/linux/arch/ppc/kernel/irq.c Mon May 27 11:00:58 1996 +++ new/linux/arch/ppc/kernel/irq.c Mon Jul 8 10:27:42 1996 @@ -264,7 +264,6 @@ #if 0 _printk("Request IRQ #%d, Handler: %x\n", irq, handler); -cnpause(); #endif if (irq > 15) { diff -ur --new-file old/linux/arch/ppc/kernel/misc.S new/linux/arch/ppc/kernel/misc.S --- old/linux/arch/ppc/kernel/misc.S Mon May 27 11:00:58 1996 +++ new/linux/arch/ppc/kernel/misc.S Mon Jul 8 10:27:42 1996 @@ -474,6 +474,7 @@ * Create a kernel thread * __kernel_thread(flags, fn, arg) */ +#if 0 #define SYS_CLONE 120 _GLOBAL(__kernel_thread) __kernel_thread: @@ -484,7 +485,7 @@ mtlr r4 mr r3,r5 blr - +#endif /* Why isn't this a) automatic, b) written in 'C'? */ .data .align 4 @@ -652,5 +653,7 @@ .long sys_sched_get_priority_max .long sys_sched_get_priority_min /* 160 */ .long sys_sched_rr_get_interval - .space (NR_syscalls-162)*4 + .long sys_nanosleep + .long sys_mremap + .space (NR_syscalls-163)*4 diff -ur --new-file old/linux/arch/ppc/kernel/mk_defs.c new/linux/arch/ppc/kernel/mk_defs.c --- old/linux/arch/ppc/kernel/mk_defs.c Mon May 27 11:00:58 1996 +++ new/linux/arch/ppc/kernel/mk_defs.c Mon Jul 8 10:27:42 1996 @@ -2,7 +2,7 @@ * This program is used to generate definitions needed by * assembly language modules. */ - +#define MK_DEFS #include #include diff -ur --new-file old/linux/arch/ppc/kernel/mk_ramdisk.c new/linux/arch/ppc/kernel/mk_ramdisk.c --- old/linux/arch/ppc/kernel/mk_ramdisk.c Sat Dec 30 14:48:22 1995 +++ new/linux/arch/ppc/kernel/mk_ramdisk.c Thu Jan 1 01:00:00 1970 @@ -1,65 +0,0 @@ -#include - -extern long ce_exec_config[]; - -main(int argc, char *argv[]) -{ - FILE *out, *in; - int i, cnt, pos; - unsigned char *lp; - unsigned char buf[4096]; - if (argc != 3) - { - fprintf(stderr, "usage: %s \n", argv[0]); - exit(1); - } - if ((out = fopen(argv[2], "w")) == (FILE *)0) - { - fprintf(stderr, "Can't create '%s'\n", argv[2]); - exit(1); - } - if ((in = fopen(argv[1], "r")) == (FILE *)0) - { - fprintf(stderr, "Can't open '%s'\n", argv[1]); - exit(1); - } - fprintf(out, "#\n"); - fprintf(out, "# Miscellaneous data structures:\n"); - fprintf(out, "# WARNING - this file is automatically generated!\n"); - fprintf(out, "#\n"); - fprintf(out, "\n"); - fprintf(out, "\t.data\n"); - fprintf(out, "\t.globl builtin_ramdisk_image\n"); - fprintf(out, "builtin_ramdisk_image:\n"); - pos = 0; - while (fread(buf, sizeof(buf), 1, in) == 1) - { - cnt = 0; - lp = (unsigned char *)buf; - for (i = 0; i < sizeof(buf); i += 4) - { - if (cnt == 0) - { - fprintf(out, "\t.long\t"); - } - fprintf(out, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]); - lp += 4; - if (++cnt == 4) - { - cnt = 0; - fprintf(out, " # %x \n", pos+i-12); - fflush(out); - } else - { - fprintf(out, ","); - } - } - pos += sizeof(buf); - } - fprintf(out, "\t.globl builtin_ramdisk_size\n"); - fprintf(out, "builtin_ramdisk_size:\t.long\t0x%x\n", pos); - fflush(out); - fclose(out); - exit(0); -} - diff -ur --new-file old/linux/arch/ppc/kernel/mkboot.c new/linux/arch/ppc/kernel/mkboot.c --- old/linux/arch/ppc/kernel/mkboot.c Mon May 27 11:00:58 1996 +++ new/linux/arch/ppc/kernel/mkboot.c Thu Jan 1 01:00:00 1970 @@ -1,269 +0,0 @@ -/* - * mkboot - Make a 'boot' image from a PowerPC (ELF) binary - * - * usage: mkboot - * - */ - -#include -#include -#include -#include -#include - -#define MAX_SECTIONS 64 -int fd; -Elf32_External_Ehdr hdr; -Elf32_External_Shdr sections[MAX_SECTIONS]; -char *symtab; - -/* Boolean type definitions */ - -#define FALSE 0 -#define TRUE 1 -#define bool short - -extern char *strerror(); -extern int errno; - -#define ADDR unsigned long - -/* Definitions that control the shape of the output */ -#define MAX_ITEMS 32 /* Max # bytes per line */ - -FILE *in_file; /* Input (binary image) file */ -FILE *out_file; /* Output (boot image) file */ - -int org = -1; - -#ifdef linux -long -_LONG(unsigned long *p) -{ - unsigned char *xp = (unsigned char *)p; - return ((xp[0]<<24) | (xp[1]<<16) | (xp[2]<<8) | xp[3]); -} - -unsigned short -_USHORT(unsigned short *p) -{ - unsigned char *xp = (unsigned char *)p; - return ((xp[0]<<8) | xp[1]); -} -#else -#define _LONG * -#define _USHORT * -#endif - -Elf32_External_Shdr * -find_section(char *section_name) -{ - Elf32_External_Shdr *shdr = sections; - int i; - for (i = 0; i < MAX_SECTIONS; i++, shdr++) - { - if (strcmp(section_name, &symtab[_LONG((int *)shdr->sh_name)]) == 0) - { - return (shdr); - } - } - return ((Elf32_External_Shdr *)0); -} - -main (argc, argv) - int argc; - char *argv[]; -{ - if ((argc == 3) || (argc == 4)) - { - if (argc == 4) - { - org = strtol(argv[3], NULL, 0); - } - if (init(argc, argv)) - { - process(argv[2]); - } - else exit(255); - } else - { /* Illegal command line */ - fprintf(stderr, "Syntax: mkboot \n"); - exit(255); - } - exit(0); -} - -init(argc, argv) - int argc; - char *argv[]; -{ - int sizeof_sections, size; - char *fn = argv[1]; - Elf32_External_Shdr *shdr; - if ((out_file = fopen(argv[2], "w")) == (FILE *)NULL) - { - io_err("creating output file"); - return (FALSE); - } - if ((in_file = fopen(fn, "r")) == (FILE *)NULL) - { - fprintf(stderr, "Can't open '%s': %s\n", fn, strerror(errno)); - return (FALSE); - } - if (fread(&hdr, sizeof(hdr), 1, in_file) != 1) - { - fprintf(stderr, "Can't read ELF header: %s\n", strerror(errno)); - return (FALSE); - } - /* Make sure this is a file we like */ - if ((hdr.e_ident[EI_MAG0] != ELFMAG0) || (hdr.e_ident[EI_MAG1] != ELFMAG1) || - (hdr.e_ident[EI_MAG2] != ELFMAG2) || (hdr.e_ident[EI_MAG3] != ELFMAG3)) - { - fprintf(stderr, "Invalid binary file (not ELF)\n"); - return (FALSE); - } - if (hdr.e_ident[EI_CLASS] != ELFCLASS32) - { - fprintf(stderr, "Invalid binary file (not ELF32)\n"); - return (FALSE); - } - if ((_USHORT((unsigned short *)hdr.e_machine) != EM_CYGNUS_POWERPC) && - (_USHORT((unsigned short *)hdr.e_machine) != EM_PPC)) - { - fprintf(stderr, "Invalid binary file (not PowerPC)\n"); - return (FALSE); - } - if (_USHORT((unsigned short *)hdr.e_shnum) > MAX_SECTIONS) - { - fprintf(stderr, "Invalid binary file (too many sections)\n"); - return (FALSE); - } - fseek(in_file, _LONG((int *)hdr.e_shoff), 0); - sizeof_sections = _USHORT((unsigned short *)hdr.e_shnum) * sizeof(sections[0]); - if (fread(sections, sizeof_sections, 1, in_file) != 1) - { - fprintf(stderr, "Can't read sections: %s\n", strerror(errno)); - return (FALSE); - } - /* Read in symbol table */ - shdr = §ions[_USHORT((unsigned short *)hdr.e_shstrndx)]; - size = _LONG((int *)shdr->sh_size); - if (!(symtab = malloc(256))) - { - fprintf(stderr, "Can't allocate memory for symbol table.\n"); - return (FALSE); - } - fseek(in_file, _LONG((int *)shdr->sh_offset), 0); - if (fread(symtab, size, 1, in_file) != 1) - { - fprintf(stderr, "Can't read symbol table: %s\n", strerror(errno)); - return (FALSE); - } - return (TRUE); -} - -process(out_name) - char *out_name; -{ - Elf32_External_Shdr *shdr_text, *shdr_data; - long relocated_text_base, text_base, text_offset, text_size; - long relocated_data_base, data_base, data_offset, data_size; - shdr_text = find_section(".text"); - shdr_data = find_section(".data"); - text_base = relocated_text_base = _LONG((int *)shdr_text->sh_addr); - text_size = _LONG((int *)shdr_text->sh_size); - text_offset = _LONG((int *)shdr_text->sh_offset); - data_base = relocated_data_base = _LONG((int *)shdr_data->sh_addr); - data_size = _LONG((int *)shdr_data->sh_size); - data_offset = _LONG((int *)shdr_data->sh_offset); - if (org >= 0) - { - relocated_text_base = org; - relocated_data_base = data_base - text_base + org; - } -fprintf(stderr, "TEXT %x bytes at %x[%x]\n", text_size, text_base, relocated_text_base); -fprintf(stderr, "DATA %x bytes at %x[%x]\n", data_size, data_base, relocated_data_base); - if (dump_segment(text_offset, relocated_text_base, text_size) && - dump_segment(data_offset, relocated_data_base, data_size)) - { - } else - { - unlink(out_name); - } -} - -dump_segment(off, base, size) - long off; - ADDR base; - long size; -{ - char buf[4096]; - int len; - bool ok = TRUE; -fprintf(stderr, "Reading %x bytes at %x.%x\n", size, off, base); - fseek(in_file, 0, 0); - fseek(in_file, off, 0); -#if 0 - if (org >= 0) - { - fseek(out_file, base+org, 0); - } else - { - fseek(out_file, base, 0); - } -#else - fseek(out_file, base, 0); -#endif - while (size && ok) - { - len = size; - if (len > sizeof(buf)) - { - len = sizeof(buf); - } - if (fread(buf, sizeof(char), len, in_file) == len) - { - fwrite(buf, sizeof(char), len, out_file); - } else - { - fprintf(stderr,"Premature EOF encountered.\n"); - ok = FALSE; - } - size -= len; - } - return (ok); -} - -io_err(what) - char *what; -{ - fprintf(stderr, "Error %s: %s\n", what, strerror(errno)); -} - - - -#ifdef sun -extern int sys_nerr; -extern char *sys_errlist[]; - -char * -strerror(int errno) -{ - static char msg[32]; - if (errno <= sys_nerr) - { - return (sys_errlist[errno]); - } else - { - sprintf(msg, "<>", errno); - return (msg); - } -} - -strtoul(char *str, char **radix, int base) -{ - return(strtol(str, radix, base)); -} -#endif - - diff -ur --new-file old/linux/arch/ppc/kernel/mmu.h new/linux/arch/ppc/kernel/mmu.h --- old/linux/arch/ppc/kernel/mmu.h Mon May 27 11:00:58 1996 +++ new/linux/arch/ppc/kernel/mmu.h Thu Jan 1 01:00:00 1970 @@ -1,160 +0,0 @@ -/* - * PowerPC memory management structures - */ - -#ifndef _PPC_MMU_H_ -#define _PPC_MMU_H_ - -/* Hardware Page Table Entry */ - -typedef struct _PTE - { - unsigned long v:1; /* Entry is valid */ - unsigned long vsid:24; /* Virtual segment identifier */ - unsigned long h:1; /* Hash algorithm indicator */ - unsigned long api:6; /* Abbreviated page index */ - unsigned long rpn:20; /* Real (physical) page number */ - unsigned long :3; /* Unused */ - unsigned long r:1; /* Referenced */ - unsigned long c:1; /* Changed */ - unsigned long w:1; /* Write-thru cache mode */ - unsigned long i:1; /* Cache inhibited */ - unsigned long m:1; /* Memory coherence */ - unsigned long g:1; /* Guarded */ - unsigned long :1; /* Unused */ - unsigned long pp:2; /* Page protection */ - } PTE; - -/* Values for PP (assumes Ks=0, Kp=1) */ -#define PP_RWXX 0 /* Supervisor read/write, User none */ -#define PP_RWRX 1 /* Supervisor read/write, User read */ -#define PP_RWRW 2 /* Supervisor read/write, User read/write */ -#define PP_RXRX 3 /* Supervisor read, User read */ - -/* Segment Register */ - -typedef struct _SEGREG - { - unsigned long t:1; /* Normal or I/O type */ - unsigned long ks:1; /* Supervisor 'key' (normally 0) */ - unsigned long kp:1; /* User 'key' (normally 1) */ - unsigned long n:1; /* No-execute */ - unsigned long :4; /* Unused */ - unsigned long vsid:24; /* Virtual Segment Identifier */ - } SEGREG; - -/* Block Address Translation (BAT) Registers */ - -typedef struct _BATU /* Upper part of BAT */ - { - unsigned long bepi:15; /* Effective page index (virtual address) */ - unsigned long :4; /* Unused */ - unsigned long bl:11; /* Block size mask */ - unsigned long vs:1; /* Supervisor valid */ - unsigned long vp:1; /* User valid */ - } BATU; - -typedef struct _BATL /* Lower part of BAT */ - { - unsigned long brpn:15; /* Real page index (physical address) */ - unsigned long :10; /* Unused */ - unsigned long w:1; /* Write-thru cache */ - unsigned long i:1; /* Cache inhibit */ - unsigned long m:1; /* Memory coherence */ - unsigned long g:1; /* Guarded (MBZ) */ - unsigned long :1; /* Unused */ - unsigned long pp:2; /* Page access protections */ - } BATL; - -typedef struct _BAT - { - BATU batu; /* Upper register */ - BATL batl; /* Lower register */ - } BAT; - -/* Block size masks */ -#define BL_128K 0x000 -#define BL_256K 0x001 -#define BL_512K 0x003 -#define BL_1M 0x007 -#define BL_2M 0x00F -#define BL_4M 0x01F -#define BL_8M 0x03F -#define BL_16M 0x07F -#define BL_32M 0x0FF -#define BL_64M 0x1FF -#define BL_128M 0x3FF -#define BL_256M 0x7FF - -/* BAT Access Protection */ -#define BPP_XX 0x00 /* No access */ -#define BPP_RX 0x01 /* Read only */ -#define BPP_RW 0x02 /* Read/write */ - -/* - * Simulated two-level MMU. This structure is used by the kernel - * to keep track of MMU mappings and is used to update/maintain - * the hardware HASH table which is really a cache of mappings. - * - * The simulated structures mimic the hardware available on other - * platforms, notably the 80x86 and 680x0. - */ - -typedef struct _pte - { - unsigned long page_num:20; - unsigned long unused:6; - unsigned long acc:3; /* Read/write/execute permissions */ - unsigned long r:1; /* Page has been referenced */ - unsigned long m:1; /* Page has been modified */ - unsigned long v:1; /* Entry is valid */ - } pte; - -#define ACC_Rxx 0x04 -#define ACC_xWx 0x02 -#define ACC_xxX 0x01 -#define ACC_RWX (ACC_Rxx|ACC_xWx|ACC_xxX) - -#define PD_SHIFT (10+12) /* Page directory */ -#define PD_MASK 0x02FF -#define PT_SHIFT (12) /* Page Table */ -#define PT_MASK 0x02FF -#define PG_SHIFT (12) /* Page Entry */ - - -/* MMU context */ - -typedef struct _MMU_context - { - SEGREG segs[16]; /* Segment registers */ - pte **pmap; /* Two-level page-map structure */ - } MMU_context; - -#if 0 -BAT ibat[4]; /* Instruction BAT images */ -BAT dbat[4]; /* Data BAT images */ -PTE *hash_table; /* Hardware hashed page table */ -int hash_table_size; -int hash_table_mask; -unsigned long sdr; /* Hardware image of SDR */ -#endif - -/* Used to set up SDR register */ -#define HASH_TABLE_SIZE_64K 0x00010000 -#define HASH_TABLE_SIZE_128K 0x00020000 -#define HASH_TABLE_SIZE_256K 0x00040000 -#define HASH_TABLE_SIZE_512K 0x00080000 -#define HASH_TABLE_SIZE_1M 0x00100000 -#define HASH_TABLE_SIZE_2M 0x00200000 -#define HASH_TABLE_SIZE_4M 0x00400000 -#define HASH_TABLE_MASK_64K 0x000 -#define HASH_TABLE_MASK_128K 0x001 -#define HASH_TABLE_MASK_256K 0x003 -#define HASH_TABLE_MASK_512K 0x007 -#define HASH_TABLE_MASK_1M 0x00F -#define HASH_TABLE_MASK_2M 0x01F -#define HASH_TABLE_MASK_4M 0x03F - -#define MMU_PAGE_SIZE 4096 - -#endif diff -ur --new-file old/linux/arch/ppc/kernel/newppcdefs.h new/linux/arch/ppc/kernel/newppcdefs.h --- old/linux/arch/ppc/kernel/newppcdefs.h Thu Oct 26 03:01:07 1995 +++ new/linux/arch/ppc/kernel/newppcdefs.h Thu Jan 1 01:00:00 1970 @@ -1,114 +0,0 @@ -/* - * WARNING! This file is automatically generated - DO NOT EDIT! - */ -#define STATE 0 -#define COUNTER 4 -#define BLOCKED 16 -#define SIGNAL 12 -#define KERNEL_STACK_PAGE 88 -#define TSS 504 -#define KSP 0 -#define MMU_SEG0 8 -#define MMU_SEG1 12 -#define MMU_SEG2 16 -#define MMU_SEG3 20 -#define MMU_SEG4 24 -#define MMU_SEG5 28 -#define MMU_SEG6 32 -#define MMU_SEG7 36 -#define MMU_SEG8 40 -#define MMU_SEG9 44 -#define MMU_SEG10 48 -#define MMU_SEG11 52 -#define MMU_SEG12 56 -#define MMU_SEG13 60 -#define MMU_SEG14 64 -#define MMU_SEG15 68 -#define TSS_FPR0 72 -#define TSS_FPR1 80 -#define TSS_FPR2 88 -#define TSS_FPR3 96 -#define TSS_FPR4 104 -#define TSS_FPR5 112 -#define TSS_FPR6 120 -#define TSS_FPR7 128 -#define TSS_FPR8 136 -#define TSS_FPR9 144 -#define TSS_FPR10 152 -#define TSS_FPR11 160 -#define TSS_FPR12 168 -#define TSS_FPR13 176 -#define TSS_FPR14 184 -#define TSS_FPR15 192 -#define TSS_FPR16 200 -#define TSS_FPR17 208 -#define TSS_FPR18 216 -#define TSS_FPR19 224 -#define TSS_FPR20 232 -#define TSS_FPR21 240 -#define TSS_FPR22 248 -#define TSS_FPR23 256 -#define TSS_FPR24 264 -#define TSS_FPR25 272 -#define TSS_FPR26 280 -#define TSS_FPR27 288 -#define TSS_FPR28 296 -#define TSS_FPR29 304 -#define TSS_FPR30 312 -#define TSS_FPR31 320 -#define INT_FRAME_SIZE 384 -#define GPR0 56 -#define GPR1 60 -#define GPR2 64 -#define GPR3 68 -#define GPR4 72 -#define GPR5 76 -#define GPR6 80 -#define GPR7 84 -#define GPR8 88 -#define GPR9 92 -#define GPR10 96 -#define GPR11 100 -#define GPR12 104 -#define GPR13 108 -#define GPR14 112 -#define GPR15 116 -#define GPR16 120 -#define GPR17 124 -#define GPR18 128 -#define GPR19 132 -#define GPR20 136 -#define GPR21 140 -#define GPR22 144 -#define GPR23 148 -#define GPR24 152 -#define GPR25 156 -#define GPR26 160 -#define GPR27 164 -#define GPR28 168 -#define GPR29 172 -#define GPR30 176 -#define GPR31 180 -#define FPR0 256 -#define FPR1 264 -#define FPR2 272 -#define FPR3 280 -#define FPCSR 288 -#define _NIP 184 -#define _MSR 188 -#define _CTR 192 -#define _LINK 196 -#define _CCR 200 -#define _XER 208 -#define _DAR 212 -#define _DSISR 216 -#define _HASH1 220 -#define _HASH2 224 -#define _IMISS 228 -#define _DMISS 232 -#define _ICMP 236 -#define _DCMP 240 -#define ORIG_GPR3 244 -#define RESULT 248 -#define TRAP 296 -#define MARKER 300 diff -ur --new-file old/linux/arch/ppc/kernel/no_ramdisk.S new/linux/arch/ppc/kernel/no_ramdisk.S --- old/linux/arch/ppc/kernel/no_ramdisk.S Mon May 27 11:00:58 1996 +++ new/linux/arch/ppc/kernel/no_ramdisk.S Thu Jan 1 01:00:00 1970 @@ -1,6 +0,0 @@ - .data - .globl builtin_ramdisk_image -builtin_ramdisk_image: - .globl builtin_ramdisk_size -builtin_ramdisk_size: .long 0 - diff -ur --new-file old/linux/arch/ppc/kernel/ppc_asm.tmpl new/linux/arch/ppc/kernel/ppc_asm.tmpl --- old/linux/arch/ppc/kernel/ppc_asm.tmpl Mon May 27 11:00:58 1996 +++ new/linux/arch/ppc/kernel/ppc_asm.tmpl Mon Jul 8 10:27:43 1996 @@ -165,4 +165,4 @@ /* Missing instructions */ #define bdne bc 0,2, -#include "ppc_machine.h" +#include "asm/ppc_machine.h" diff -ur --new-file old/linux/arch/ppc/kernel/ppc_machine.h new/linux/arch/ppc/kernel/ppc_machine.h --- old/linux/arch/ppc/kernel/ppc_machine.h Tue May 28 06:46:04 1996 +++ new/linux/arch/ppc/kernel/ppc_machine.h Thu Jan 1 01:00:00 1970 @@ -1,50 +0,0 @@ -/* - * PowerPC machine specifics - */ - -#ifndef _PPC_MACHINE_H_ -#define _PPC_MACHINE_H_ - -/* Bit encodings for Machine State Register (MSR) */ -#define MSR_POW (1<<18) /* Enable Power Management */ -#define MSR_TGPR (1<<17) /* TLB Update registers in use */ -#define MSR_ILE (1<<16) /* Interrupt Little-Endian enable */ -#define MSR_EE (1<<15) /* External Interrupt enable */ -#define MSR_PR (1<<14) /* Supervisor/User privilege */ -#define MSR_FP (1<<13) /* Floating Point enable */ -#define MSR_ME (1<<12) /* Machine Check enable */ -#define MSR_FE0 (1<<11) /* Floating Exception mode 0 */ -#define MSR_SE (1<<10) /* Single Step */ -#define MSR_BE (1<<9) /* Branch Trace */ -#define MSR_FE1 (1<<8) /* Floating Exception mode 1 */ -#define MSR_IP (1<<6) /* Exception prefix 0x000/0xFFF */ -#define MSR_IR (1<<5) /* Instruction MMU enable */ -#define MSR_DR (1<<4) /* Data MMU enable */ -#define MSR_RI (1<<1) /* Recoverable Exception */ -#define MSR_LE (1<<0) /* Little-Endian enable */ - -#define MSR_ MSR_FP|MSR_FE0|MSR_FE1|MSR_ME -#define MSR_USER MSR_|MSR_PR|MSR_EE|MSR_IR|MSR_DR - -/* Bit encodings for Hardware Implementation Register (HID0) */ -#define HID0_EMCP (1<<31) /* Enable Machine Check pin */ -#define HID0_EBA (1<<29) /* Enable Bus Address Parity */ -#define HID0_EBD (1<<28) /* Enable Bus Data Parity */ -#define HID0_SBCLK (1<<27) -#define HID0_EICE (1<<26) -#define HID0_ECLK (1<<25) -#define HID0_PAR (1<<24) -#define HID0_DOZE (1<<23) -#define HID0_NAP (1<<22) -#define HID0_SLEEP (1<<21) -#define HID0_DPM (1<<20) -#define HID0_ICE (1<<15) /* Instruction Cache Enable */ -#define HID0_DCE (1<<14) /* Data Cache Enable */ -#define HID0_ILOCK (1<<13) /* Instruction Cache Lock */ -#define HID0_DLOCK (1<<12) /* Data Cache Lock */ -#define HID0_ICFI (1<<11) /* Instruction Cache Flash Invalidate */ -#define HID0_DCI (1<<10) /* Data Cache Invalidate */ -#define HID0_SIED (1<<7) /* Serial Instruction Execution [Disable] */ -#define HID0_BHTE (1<<2) /* Branch History Table Enable */ - -#endif diff -ur --new-file old/linux/arch/ppc/kernel/ppc_machine.h.isin.processor.h new/linux/arch/ppc/kernel/ppc_machine.h.isin.processor.h --- old/linux/arch/ppc/kernel/ppc_machine.h.isin.processor.h Fri Apr 12 08:49:30 1996 +++ new/linux/arch/ppc/kernel/ppc_machine.h.isin.processor.h Thu Jan 1 01:00:00 1970 @@ -1,48 +0,0 @@ -/* - * PowerPC machine specifics - */ - -#ifndef _PPC_MACHINE_H_ -#define _PPC_MACHINE_H_ - -/* Bit encodings for Machine State Register (MSR) */ -#define MSR_POW (1<<18) /* Enable Power Management */ -#define MSR_TGPR (1<<17) /* TLB Update registers in use */ -#define MSR_ILE (1<<16) /* Interrupt Little-Endian enable */ -#define MSR_EE (1<<15) /* External Interrupt enable */ -#define MSR_PR (1<<14) /* Supervisor/User privilege */ -#define MSR_FP (1<<13) /* Floating Point enable */ -#define MSR_ME (1<<12) /* Machine Check enable */ -#define MSR_FE0 (1<<11) /* Floating Exception mode 0 */ -#define MSR_SE (1<<10) /* Single Step */ -#define MSR_BE (1<<9) /* Branch Trace */ -#define MSR_FE1 (1<<8) /* Floating Exception mode 1 */ -#define MSR_IP (1<<6) /* Exception prefix 0x000/0xFFF */ -#define MSR_IR (1<<5) /* Instruction MMU enable */ -#define MSR_DR (1<<4) /* Data MMU enable */ -#define MSR_RI (1<<1) /* Recoverable Exception */ -#define MSR_LE (1<<0) /* Little-Endian enable */ - -#define MSR_ MSR_FP|MSR_FE0|MSR_FE1|MSR_ME -#define MSR_USER MSR_|MSR_PR|MSR_EE|MSR_IR|MSR_DR - -/* Bit encodings for Hardware Implementation Register (HID0) */ -#define HID0_EMCP (1<<31) /* Enable Machine Check pin */ -#define HID0_EBA (1<<29) /* Enable Bus Address Parity */ -#define HID0_EBD (1<<28) /* Enable Bus Data Parity */ -#define HID0_SBCLK (1<<27) -#define HID0_EICE (1<<26) -#define HID0_ECLK (1<<25) -#define HID0_PAR (1<<24) -#define HID0_DOZE (1<<23) -#define HID0_NAP (1<<22) -#define HID0_SLEEP (1<<21) -#define HID0_DPM (1<<20) -#define HID0_ICE (1<<15) /* Instruction Cache Enable */ -#define HID0_DCE (1<<14) /* Data Cache Enable */ -#define HID0_ILOCK (1<<13) /* Instruction Cache Lock */ -#define HID0_DLOCK (1<<12) /* Data Cache Lock */ -#define HID0_ICFI (1<<11) /* Instruction Cache Flash Invalidate */ -#define HID0_DCI (1<<10) /* Data Cache Invalidate */ - -#endif diff -ur --new-file old/linux/arch/ppc/kernel/process.c new/linux/arch/ppc/kernel/process.c --- old/linux/arch/ppc/kernel/process.c Tue May 28 06:46:04 1996 +++ new/linux/arch/ppc/kernel/process.c Mon Jul 8 10:27:43 1996 @@ -26,7 +26,7 @@ #include #include -#include "ppc_machine.h" +#include int dump_fpu() @@ -44,7 +44,6 @@ #if 0 printk("Task %x(%d) -> %x(%d)", current, current->pid, new, new->pid); printk(" - IP: %x, SR: %x, SP: %x\n", regs->nip, regs->msr, regs); - cnpause(); #endif new_tss = &new->tss; old_tss = ¤t->tss; @@ -105,7 +104,6 @@ struct pt_regs * childregs; #if 0 printk("copy thread - NR: %d, Flags: %x, USP: %x, Task: %x, Regs: %x\n", nr, clone_flags, usp, p, regs); -cnpause(); #endif /* Construct segment registers */ segs = p->tss.segs; @@ -120,7 +118,6 @@ p->mm->context = (nr<<4); #if 0 printk("Setting MM[%x] Context = %x Task = %x Current = %x/%x\n", p->mm, p->mm->context, p, current, current->mm); -cnpause(); #endif } /* Last 8 are shared with kernel & everybody else... */ @@ -172,7 +169,6 @@ printk("Start thread [%x] at PC: %x, SR: %x, SP: %x\n", regs, eip, regs->msr, esp); dump_buf(esp, len); dump_buf(eip, 0x80); - cnpause(); } #endif } @@ -243,7 +239,7 @@ { printk("\n"); } - if (cnt > 16) break; + if (cnt > 32) break; } printk("\n"); } diff -ur --new-file old/linux/arch/ppc/kernel/ramdisk_drvr.c new/linux/arch/ppc/kernel/ramdisk_drvr.c --- old/linux/arch/ppc/kernel/ramdisk_drvr.c Mon May 27 11:00:58 1996 +++ new/linux/arch/ppc/kernel/ramdisk_drvr.c Thu Jan 1 01:00:00 1970 @@ -1,84 +0,0 @@ -/* - * linux/kernel/blk_drv/ramdisk.c - * - * Written by Theodore Ts'o, 12/2/91 - * - * Modifications by Fred N. van Kempen to allow for bootable root - * disks (which are used in LINUX/Pro). Also some cleanups. 03/03/93 - */ - - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define MAJOR_NR MEM_MAJOR -#include - -#define RAMDISK_MINOR 1 - -char *rd_start; -int rd_length = 0; -static int rd_blocksizes[2] = {0, 0}; - -static void rd_request(void) -{ - int len; - char *addr; - -repeat: - INIT_REQUEST; - addr = rd_start + (CURRENT->sector << 9); - len = CURRENT->current_nr_sectors << 9; - - if (CURRENT-> cmd == WRITE) { - (void ) memcpy(addr, - CURRENT->buffer, - len); - } else if (CURRENT->cmd == READ) { - (void) memcpy(CURRENT->buffer, - addr, - len); - } else - panic("RAMDISK: unknown RAM disk command !\n"); - end_request(1); - goto repeat; -} - -static struct file_operations rd_fops = { - NULL, /* lseek - default */ - block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ - NULL, /* readdir - bad */ - NULL, /* select */ - NULL, /* ioctl */ - NULL, /* mmap */ - NULL, /* no special open code */ - NULL, /* no special release code */ - block_fsync /* fsync */ -}; - -void -rd_preloaded_init(char *start, int length) -{ - int i; - - if (register_blkdev(MEM_MAJOR,"rd",&rd_fops)) { - printk("RAMDISK: Unable to get major %d.\n", MEM_MAJOR); - return 0; - } - blk_dev[MEM_MAJOR].request_fn = DEVICE_REQUEST; - rd_start = start; - rd_length = length; - for(i=0;i<2;i++) rd_blocksizes[i] = 1024; - blksize_size[MAJOR_NR] = rd_blocksizes; - /* We loaded the file system image. Prepare for mounting it. */ - ROOT_DEV = to_kdev_t((MEM_MAJOR << 8) | RAMDISK_MINOR); -} diff -ur --new-file old/linux/arch/ppc/kernel/setup.c new/linux/arch/ppc/kernel/setup.c --- old/linux/arch/ppc/kernel/setup.c Mon May 27 11:00:58 1996 +++ new/linux/arch/ppc/kernel/setup.c Mon Jul 8 10:27:43 1996 @@ -21,6 +21,7 @@ #include #include #include +#include #define SIO_CONFIG_RA 0x398 #define SIO_CONFIG_RD 0x399 @@ -35,26 +36,33 @@ extern int root_mountflags; unsigned char aux_device_present; +#ifdef CONFIG_BLK_DEV_RAM +extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */ +extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */ +extern int rd_image_start; /* starting block # of image */ +#endif /* * The format of "screen_info" is strange, and due to early * i386-setup code. This is just enough to make the console * code think we're on a EGA+ colour display. */ + /* this is changed only in minor ways from the original + -- Cort + */ struct screen_info screen_info = { - 0, 0, /* orig-x, orig-y */ - 0, 0, /* unused */ + 0, 25, /* orig-x, orig-y */ + { 0, 0 }, /* unused */ 0, /* orig-video-page */ 0, /* orig-video-mode */ 80, /* orig-video-cols */ - 0, /* unused [short] */ - 0, /* ega_bx */ - 0, /* unused [short] */ + 0,0,0, /* ega_ax, ega_bx, ega_cx */ 25, /* orig-video-lines */ - 0, /* isVGA */ - 16 /* video points */ + 1, /* orig-video-isVGA */ + 16 /* orig-video-points */ }; + unsigned long bios32_init(unsigned long memory_start, unsigned long memory_end) { return memory_start; @@ -64,8 +72,9 @@ { unsigned char dram_size = inb(0x0804); unsigned long total; -_printk("DRAM Size = %x\n", dram_size); -_printk("Config registers = %x/%x/%x/%x\n", inb(0x0800), inb(0x0801), inb(0x0802), inb(0x0803)); + extern BAT BAT2; +printk("DRAM Size = %x\n", dram_size); +printk("Config registers = %x/%x/%x/%x\n", inb(0x0800), inb(0x0801), inb(0x0802), inb(0x0803)); switch (dram_size & 0x07) { case 0: @@ -132,6 +141,16 @@ Hash_size = HASH_TABLE_SIZE_128K; Hash_mask = HASH_TABLE_MASK_128K; } + switch(total) + { + case 0x01000000: +/* BAT2[0][1] = BL_16M;*/ + break; + default: + printk("WARNING: setup.c: find_end_of_memory() unknown total ram size %x\n", total); + break; + } + Hash = (PTE *)((total-Hash_size)+KERNELBASE); bzero(Hash, Hash_size); return ((unsigned long)Hash); @@ -156,18 +175,32 @@ outb(reg, SIO_CONFIG_RD); outb(reg, SIO_CONFIG_RD); /* Have to write twice to change! */ ROOT_DEV = to_kdev_t(DEFAULT_ROOT_DEVICE); + /*ROOT_DEV = MKDEV(UNNAMED_MAJOR, 255);*/ /* nfs */ aux_device_present = 0xaa; + /*nfsaddrs=myip:serverip:gateip:netmaskip:clientname*/ + strcpy(cmd_line, + "nfsaddrs=129.138.6.13:129.138.6.90:129.138.6.1:255.255.255.0:pandora"); + /* strcpy(cmd_line,"root=/dev/sda1");*/ *cmdline_p = cmd_line; *memory_start_p = (unsigned long) &_end; *memory_end_p = (unsigned long *)end_of_DRAM; size_memory = *memory_end_p - KERNELBASE; /* Relative size of memory */ + +#ifdef CONFIG_BLK_DEV_RAM + rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK; + rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); + rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); + rd_prompt = 0; + rd_doload = 0; + rd_image_start = 0; +#endif } asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on) { return -EIO; } - +#if 0 extern char builtin_ramdisk_image; extern long builtin_ramdisk_size; @@ -182,7 +215,7 @@ root_mountflags |= MS_RDONLY; } } - +#endif #define MAJOR(n) (((n)&0xFF00)>>8) #define MINOR(n) ((n)&0x00FF) diff -ur --new-file old/linux/arch/ppc/kernel/signal.c new/linux/arch/ppc/kernel/signal.c --- old/linux/arch/ppc/kernel/signal.c Mon May 27 11:00:58 1996 +++ new/linux/arch/ppc/kernel/signal.c Mon Jul 8 10:27:43 1996 @@ -30,7 +30,7 @@ mask = current->blocked; current->blocked = set & _BLOCKABLE; regs->gpr[3] = -EINTR; -#if 0 +#if 0 printk("Task: %x[%d] - SIGSUSPEND at %x, Mask: %x\n", current, current->pid, regs->nip, set); #endif while (1) { @@ -107,7 +107,6 @@ struct sigcontext_struct *sc; struct sigaction * sa; int s = _disable_interrupts(); - while ((signr = current->signal & mask)) { #if 0 signr = ffz(~signr); /* Compute bit # */ diff -ur --new-file old/linux/arch/ppc/kernel/stubs.c new/linux/arch/ppc/kernel/stubs.c --- old/linux/arch/ppc/kernel/stubs.c Mon May 27 11:00:58 1996 +++ new/linux/arch/ppc/kernel/stubs.c Mon Jul 8 10:27:43 1996 @@ -9,20 +9,20 @@ halt() { - _printk("\n...Halt!\n"); + printk("\n...Halt!\n"); abort(); } _panic(char *msg) { - _printk("Panic: %s\n", msg); + printk("Panic: %s\n", msg); printk("Panic: %s\n", msg); abort(); } _warn(char *msg) { - _printk("*** Warning: %s UNIMPLEMENTED!\n", msg); + printk("*** Warning: %s UNIMPLEMENTED!\n", msg); } diff -ur --new-file old/linux/arch/ppc/kernel/test.S new/linux/arch/ppc/kernel/test.S --- old/linux/arch/ppc/kernel/test.S Mon Dec 11 06:41:59 1995 +++ new/linux/arch/ppc/kernel/test.S Thu Jan 1 01:00:00 1970 @@ -1,100 +0,0 @@ -#include "ppc_asm.tmpl" -#include "ppc_defs.h" - -#define SYNC() \ - isync; \ - sync - -#define BEEF ori r0,r0,0; ori r0,r0,0 ;.word 0 ; .word 0xBEEF -_BEG: - lis r7,0xF000 /* To mask upper 4 bits */ - - -/* Initialize BAT registers */ - lis r3,OFF_BAT@h - ori r3,r3,OFF_BAT@l - andc r3,r3,r7 /* make unmapped address */ - lwz r0,0(r3) - - mtspr IBAT0U,r0 - mtspr DBAT0U,r0 - lwz r0,4(r3) - mtspr IBAT0L,r0 - mtspr DBAT0L,r0 - - lis r3,OFF_BAT@h - ori r3,r3,OFF_BAT@l - andc r3,r3,r7 /* make unmapped address */ - lwz r0,0(r3) - mtspr IBAT1U,r0 - mtspr DBAT1U,r0 - lwz r0,4(r3) - mtspr IBAT1L,r0 - mtspr DBAT1L,r0 - - lis r3,ZERO_BAT@h - ori r3,r3,ZERO_BAT@l - andc r3,r3,r7 /* make unmapped address */ - lwz r0,0(r3) - mtspr IBAT2U,r0 - mtspr DBAT2U,r0 - lwz r0,4(r3) - mtspr IBAT2L,r0 - mtspr DBAT2L,r0 - - - lis r3,TMP_BAT2@h - ori r3,r3,TMP_BAT2@l - andc r3,r3,r7 /* make unmapped address */ - lwz r0,0(r3) - mtspr IBAT3U,r0 - mtspr DBAT3U,r0 - lwz r0,4(r3) - mtspr IBAT3L,r0 - mtspr DBAT3L,r0 - - -/* Now we can turn on the MMU */ -/* set srr1 for rfi */ - mfmsr r3 - ori r3,r3,MSR_DR|MSR_IR|MSR_ - - mtspr SRR1,r3 - -/* set srr0 for rfi */ - subf r2, r2, r2 -/* lis r2,10f@h*/ - lis r2,0 - ori r2,r2,10f@l - mtspr SRR0,r2 - - SYNC() - rfi - - ori r0, r0, 0 - ori r0, r0, 0 -10: ori r0, r0, 0 - ori r0, r0, 0 - BEEF - -#if 0 -/* check bptr to see if it actually has the correct values */ - - subf r2,r2,r2 - lis r2,bptr@h - ori r2,r2,bptr@l - lwz r0,0(r2) - -/* rfi to the beef */ - mtspr SRR1,r3 - mtspr SRR0,r2 - - SYNC() - rfi - -bptr: ori r0, r0, 0 - BEEF - BEEF - BEEF -#endif -_END: diff -ur --new-file old/linux/arch/ppc/kernel/test1.c new/linux/arch/ppc/kernel/test1.c --- old/linux/arch/ppc/kernel/test1.c Sat Oct 14 22:42:46 1995 +++ new/linux/arch/ppc/kernel/test1.c Thu Jan 1 01:00:00 1970 @@ -1,145 +0,0 @@ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/*pgd_t *swapper_pg_dir;*/ - - - -BAT BAT0 = - { - { - 0x80000000>>17, /* bepi */ - BL_256M, /* bl */ - 1, /* vs */ - 1, /* vp */ - }, - { - 0x80000000>>17, /* brpn */ - 1, /* w */ - 1, /* i (cache disabled) */ - 0, /* m */ - 0, /* g */ - BPP_RW /* pp */ - } - }; -BAT BAT1 = - { - { - 0xC0000000>>17, /* bepi */ - BL_256M, /* bl */ - 1, /* vs */ - 1, /* vp */ - }, - { - 0xC0000000>>17, /* brpn */ - 1, /* w */ - 1, /* i (cache disabled) */ - 0, /* m */ - 0, /* g */ - BPP_RW /* pp */ - } - }; -BAT BAT2 = - { - { - 0x00000000>>17, /* bepi */ - BL_256M, /* bl */ - 0, /* vs */ - 0, /* vp */ - }, - { - 0x00000000>>17, /* brpn */ - 1, /* w */ - 1, /* i (cache disabled) */ - 0, /* m */ - 0, /* g */ - BPP_RW /* pp */ - } - }; -BAT BAT3 = - { - { - 0x00000000>>17, /* bepi */ - BL_256M, /* bl */ - 0, /* vs */ - 0, /* vp */ - }, - { - 0x00000000>>17, /* brpn */ - 1, /* w */ - 1, /* i (cache disabled) */ - 0, /* m */ - 0, /* g */ - BPP_RW /* pp */ - } - }; - - -BAT TMP_BAT2 = - { /* 0x9XXXXXXX -> 0x0XXXXXXX */ - { - 0x90000000>>17, /* bepi */ - BL_256M, /* bl */ - 1, /* vs */ - 1, /* vp */ - }, - { - 0x00000000>>17, /* brpn */ - 1, /* w */ - 0, /* i (cache enabled) */ - 0, /* m */ - 0, /* g */ - BPP_RW /* pp */ - } - }; - - - -BAT ZERO_BAT = - { /* 0x0XXXXXXX -> 0x0XXXXXXX */ - { - 0x00000000>>17, /* bepi */ - BL_256M, /* bl */ - 1, /* vs */ - 1, /* vp */ - }, - { - 0x00000000>>17, /* brpn */ - 1, /* w */ - 0, /* i (cache enabled) */ - 0, /* m */ - 0, /* g */ - BPP_RW /* pp */ - } - }; - - -BAT OFF_BAT = - { /* 0x0XXXXXXX -> 0x0XXXXXXX */ - { - 0x00000000>>17, /* bepi */ - BL_256M, /* bl */ - 0, /* vs */ - 0, /* vp */ - }, - { - 0x00000000>>17, /* brpn */ - 1, /* w */ - 0, /* i (cache enabled) */ - 0, /* m */ - 0, /* g */ - BPP_RW /* pp */ - } - }; diff -ur --new-file old/linux/arch/ppc/kernel/traps.c new/linux/arch/ppc/kernel/traps.c --- old/linux/arch/ppc/kernel/traps.c Mon May 27 11:00:58 1996 +++ new/linux/arch/ppc/kernel/traps.c Mon Jul 8 10:27:43 1996 @@ -26,7 +26,7 @@ #include #include -#include "ppc_machine.h" +#include /* * Trap & Exception support @@ -40,7 +40,7 @@ void _exception(int signr, struct pt_regs *regs) { - dump_regs(regs); +/* dump_regs(regs);*/ force_sig(signr, current); if (!user_mode(regs)) { @@ -51,13 +51,13 @@ MachineCheckException(struct pt_regs *regs) { - printk("Machine check at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr); +/* printk("Machine check at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr);*/ _exception(SIGSEGV, regs); } ProgramCheckException(struct pt_regs *regs) { - printk("Program check at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr); +/* printk("Program check at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr);*/ if (current->flags & PF_PTRACED) { _exception(SIGTRAP, regs); @@ -69,30 +69,29 @@ SingleStepException(struct pt_regs *regs) { - printk("Single step at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr); +/* printk("Single step at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr);*/ regs->msr &= ~MSR_SE; /* Turn off 'trace' bit */ _exception(SIGTRAP, regs); } FloatingPointCheckException(struct pt_regs *regs) { - printk("Floating point check at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr); +/* printk("Floating point check at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr);*/ _exception(SIGFPE, regs); } AlignmentException(struct pt_regs *regs) { - printk("Alignment error at PC: %x, SR: %x\n", regs->nip, regs->msr); +/* printk("Alignment error at PC: %x, SR: %x\n", regs->nip, regs->msr); dump_regs(regs); - cnpause(); - printk("Alignment error at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr); + printk("Alignment error at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr);*/ _exception(SIGBUS, regs); } bad_stack(struct pt_regs *regs) { - printk("Kernel stack overflow at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr); - dump_regs(regs); +/* printk("Kernel stack overflow at PC: %x[%x], SR: %x\n", regs->nip, va_to_phys(regs->nip), regs->msr); + dump_regs(regs);*/ while (1) ; } @@ -130,7 +129,6 @@ if (++count == 20) { count = 0; - cnpause(); } } diff -ur --new-file old/linux/arch/ppc/mm/fault.c new/linux/arch/ppc/mm/fault.c --- old/linux/arch/ppc/mm/fault.c Mon May 27 11:00:59 1996 +++ new/linux/arch/ppc/mm/fault.c Mon Jul 8 10:27:43 1996 @@ -23,107 +23,123 @@ extern void die_if_kernel(char *, struct pt_regs *, long); extern void do_page_fault(struct pt_regs *, unsigned long, unsigned long); -#define SHOW_FAULTS -#undef SHOW_FAULTS -#define PAUSE_AFTER_FAULT -#undef PAUSE_AFTER_FAULT +#undef SHOW_FAULTS +#undef NOISY_INSTRFAULT +#undef NOISY_DATAFAULT + +#define NEWMM 1 void DataAccessException(struct pt_regs *regs) { - pgd_t *dir; - pmd_t *pmd; - pte_t *pte; - int tries, mode = 0; - if (user_mode(regs)) mode |= 0x04; - if (regs->dsisr & 0x02000000) mode |= 0x02; /* Load/store */ - if (regs->dsisr & 0x08000000) mode |= 0x01; /* Protection violation */ -#ifdef SHOW_FAULTS - printk("Data Access Fault - Loc: %x, DSISR: %x, PC: %x\n", regs->dar, regs->dsisr, regs->nip); -#ifdef PAUSE_AFTER_FAULT -cnpause(); -#endif -#endif - if (mode & 0x01) - { -#ifdef SHOW_FAULTS -printk("Write Protect Fault - Loc: %x, DSISR: %x, PC: %x\n", regs->dar, regs->dsisr, regs->nip); -#endif - do_page_fault(regs, regs->dar, mode); - return; - } - for (tries = 0; tries < 1; tries++) - { - dir = pgd_offset(current->mm, regs->dar & PAGE_MASK); - if (dir) - { - pmd = pmd_offset(dir, regs->dar & PAGE_MASK); - if (pmd && pmd_present(*pmd)) - { - pte = pte_offset(pmd, regs->dar & PAGE_MASK); - if (pte && pte_present(*pte)) - { -#ifdef SHOW_FAULTS - printk("Page mapped - PTE: %x[%x], Context: %x\n", pte, *(long *)pte, current->mm->context); -#endif - MMU_hash_page(¤t->tss, regs->dar & PAGE_MASK, pte); - return; - } - } - } else - { - printk("No PGD\n"); - } - do_page_fault(regs, regs->dar, mode); - } + pgd_t *dir; + pmd_t *pmd; + pte_t *pte; + int tries, mode = 0; + +#ifdef NOISY_DATAFAULT + printk("Data fault on %x\n",regs->dar); +#endif + + if (user_mode(regs)) mode |= 0x04; + if (regs->dsisr & 0x02000000) mode |= 0x02; /* Load/store */ + if (regs->dsisr & 0x08000000) mode |= 0x01; /* Protection violation */ + if (mode & 0x01) + { +#ifdef NOISY_DATAFAULT + printk("Write Protect fault\n "); +#endif + do_page_fault(regs, regs->dar, mode); +#ifdef NOISY_DATAFAULT + printk("Write Protect fault handled\n"); +#endif + return; + } + + + for (tries = 0; tries < 1; tries++) + { + dir = pgd_offset(current->mm, regs->dar & PAGE_MASK); + if (dir) + { + pmd = pmd_offset(dir, regs->dar & PAGE_MASK); + if (pmd && pmd_present(*pmd)) + { + pte = pte_offset(pmd, regs->dar & PAGE_MASK); + if (pte && pte_present(*pte)) + { +#if NOISY_DATAFAULT + printk("Page mapped - PTE: %x[%x]\n", pte, *(long *)pte); +#endif + MMU_hash_page(¤t->tss, regs->dar & PAGE_MASK, pte); + /*MMU_hash_page2(current->mm, regs->dar & PAGE_MASK, pte);*/ + return; + } + } + } else + { +#if NOISY_DATAFAULT + printk("No PGD\n"); +#endif + } + do_page_fault(regs, regs->dar, mode); + } } void InstructionAccessException(struct pt_regs *regs) { - pgd_t *dir; - pmd_t *pmd; - pte_t *pte; - int tries, mode = 0; - unsigned long addr = regs->nip; - if (user_mode(regs)) mode |= 0x04; -#ifdef SHOW_FAULTS - printk("Instruction Access Fault - Loc: %x, DSISR: %x, PC: %x\n", regs->dar, regs->dsisr, regs->nip); -#ifdef PAUSE_AFTER_FAULT -cnpause(); -#endif -#endif - if (mode & 0x01) - { - do_page_fault(regs, addr, mode); - return; - } - for (tries = 0; tries < 1; tries++) - { - dir = pgd_offset(current->mm, addr & PAGE_MASK); - if (dir) - { - pmd = pmd_offset(dir, addr & PAGE_MASK); - if (pmd && pmd_present(*pmd)) - { - pte = pte_offset(pmd, addr & PAGE_MASK); - if (pte && pte_present(*pte)) - { -#ifdef SHOW_FAULTS - printk("Page mapped - PTE: %x[%x], Context: %x\n", pte, *(long *)pte, current->mm->context); -#endif - MMU_hash_page(¤t->tss, addr & PAGE_MASK, pte); - return; - } - } - } else - { - printk("No PGD\n"); - } - do_page_fault(regs, addr, mode); - } + pgd_t *dir; + pmd_t *pmd; + pte_t *pte; + int tries, mode = 0; + +#if NOISY_INSTRFAULT + printk("Instr fault on %x\n",regs->dar); +#endif + +#ifdef NEWMM + if (!user_mode(regs)) + { + + panic("InstructionAcessException in kernel mode. PC %x addr %x", + regs->nip, regs->dar); + } +#endif + if (user_mode(regs)) mode |= 0x04; + if (regs->dsisr & 0x02000000) mode |= 0x02; /* Load/store */ + if (regs->dsisr & 0x08000000) mode |= 0x01; /* Protection violation */ + + if (mode & 0x01) + { + do_page_fault(regs, regs->dar, mode); + return; + } + for (tries = 0; tries < 1; tries++) + { + dir = pgd_offset(current->mm, regs->dar & PAGE_MASK); + if (dir) + { + pmd = pmd_offset(dir, regs->dar & PAGE_MASK); + if (pmd && pmd_present(*pmd)) + { + pte = pte_offset(pmd, regs->dar & PAGE_MASK); + if (pte && pte_present(*pte)) + { + + MMU_hash_page(¤t->tss, regs->dar & PAGE_MASK, pte); + /* MMU_hash_page2(current->mm, regs->dar & PAGE_MASK, pte);*/ + return; + } + } + } else + { + } + do_page_fault(regs, regs->dar, mode); + } } + /* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate @@ -137,103 +153,66 @@ */ void do_page_fault(struct pt_regs *regs, unsigned long address, unsigned long error_code) { - struct vm_area_struct * vma; - unsigned long page; + struct vm_area_struct * vma; + unsigned long page; - for (vma = current->mm->mmap ; ; vma = vma->vm_next) - { -#ifdef SHOW_FAULTS -printk("VMA(%x) - Start: %x, End: %x, Flags: %x\n", vma, vma->vm_start, vma->vm_end, vma->vm_flags); -#endif - if (!vma) - goto bad_area; - if (vma->vm_end > address) - break; - } - if (vma->vm_start <= address) - goto good_area; - if (!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; - if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur) - goto bad_area; - vma->vm_offset -= vma->vm_start - (address & PAGE_MASK); - vma->vm_start = (address & PAGE_MASK); -/* - * Ok, we have a good vm_area for this memory access, so - * we can handle it.. - */ -good_area: - /* - * was it a write? - */ - if (error_code & 2) { - if (!(vma->vm_flags & VM_WRITE)) - goto bad_area; - } else { - /* read with protection fault? */ - if (error_code & 1) - goto bad_area; - if (!(vma->vm_flags & (VM_READ | VM_EXEC))) - goto bad_area; - } - handle_mm_fault(vma, address, error_code & 2); - flush_page(address); /* Flush & Invalidate cache - note: address is OK now */ - return; + vma = find_vma(current, address); + if (!vma) + { + goto bad_area; + } + + if (vma->vm_start <= address){ + goto good_area; + } + if (!(vma->vm_flags & VM_GROWSDOWN)) + { + goto bad_area; + } + if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur) + { + goto bad_area; + } + vma->vm_offset -= vma->vm_start - (address & PAGE_MASK); -/* - * Something tried to access memory that isn't in our memory map.. - * Fix it, but check if it's kernel or user first.. - */ + vma->vm_start = (address & PAGE_MASK); + +good_area: + /* a write */ + if (error_code & 2) { + if (!(vma->vm_flags & VM_WRITE)) + { + goto bad_area; + } + /* a read */ + } else { + /* protection fault */ + if (error_code & 1) + { + goto bad_area; + } + if (!(vma->vm_flags & (VM_READ | VM_EXEC))) + { + goto bad_area; + } + } + handle_mm_fault(vma, address, error_code & 2); + flush_page(address); /* Flush & Invalidate cache - note: address is OK now */ + return; + bad_area: -printk("Task: %x, PC: %x/%x, bad area! - Addr: %x\n", current, regs->nip, current->tss.last_pc, address); -print_user_backtrace(current->tss.user_stack); -print_kernel_backtrace(); -#if 0 -cnpause(); -if (!user_mode(regs)) -{ - print_backtrace(regs->gpr[1]); -} -#endif -dump_regs(regs); - if (user_mode(regs)) { -#if 0 - current->tss.cp0_badvaddr = address; - current->tss.error_code = error_code; - current->tss.trap_no = 14; -#endif - force_sig(SIGSEGV, current); - return; - } -printk("KERNEL! Task: %x, PC: %x, bad area! - Addr: %x, PGDIR: %x\n", current, regs->nip, address, current->tss.pg_tables); -dump_regs(regs); -while (1) ; -#if 0 - /* - * Oops. The kernel tried to access some bad page. We'll have to - * terminate things with extreme prejudice. - */ - if ((unsigned long) (address-TASK_SIZE) < PAGE_SIZE) { - printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); - pg0[0] = pte_val(mk_pte(0, PAGE_SHARED)); - } else - printk(KERN_ALERT "Unable to handle kernel paging request"); - printk(" at virtual address %08lx\n",address); - page = current->tss.pg_dir; - printk(KERN_ALERT "current->tss.pg_dir = %08lx\n", page); - page = ((unsigned long *) page)[address >> PGDIR_SHIFT]; - printk(KERN_ALERT "*pde = %08lx\n", page); - if (page & 1) { - page &= PAGE_MASK; - address &= 0x003ff000; - page = ((unsigned long *) page)[address >> PAGE_SHIFT]; - printk(KERN_ALERT "*pte = %08lx\n", page); - } - die_if_kernel("Oops", regs, error_code); -#endif - do_exit(SIGKILL); + if (user_mode(regs)) + { +/* printk("Bad User Area: Addr %x PC %x Task %x pid %d %s\n", + address,regs->nip, current,current->pid,current->comm);*/ + send_sig(SIGSEGV, current, 1); + return; + } + panic("KERNEL access of bad area PC %x address %x vm_flags %x\n", + regs->nip,address,vma->vm_flags); } + va_to_phys(unsigned long address) { pgd_t *dir; @@ -260,6 +239,7 @@ } return (0); } + /* * See if an address should be valid in the current context. diff -ur --new-file old/linux/arch/ppc/mm/init.c new/linux/arch/ppc/mm/init.c --- old/linux/arch/ppc/mm/init.c Mon May 27 11:00:59 1996 +++ new/linux/arch/ppc/mm/init.c Mon Jul 8 10:27:43 1996 @@ -47,50 +47,11 @@ pte_t * __bad_pagetable(void) { panic("__bad_pagetable"); -#if 0 - extern char empty_bad_page_table[PAGE_SIZE]; - unsigned long dummy; - - __asm__ __volatile__( - ".set\tnoreorder\n\t" - "1:\tsw\t%2,(%0)\n\t" - "subu\t%1,%1,1\n\t" - "bne\t$0,%1,1b\n\t" - "addiu\t%0,%0,1\n\t" - ".set\treorder" - :"=r" (dummy), - "=r" (dummy) - :"r" (pte_val(BAD_PAGE)), - "0" ((long) empty_bad_page_table), - "1" (PTRS_PER_PAGE)); - - return (pte_t *) empty_bad_page_table; -#endif } - pte_t __bad_page(void) { panic("__bad_page"); -#if 0 - extern char empty_bad_page[PAGE_SIZE]; - unsigned long dummy; - - __asm__ __volatile__( - ".set\tnoreorder\n\t" - "1:\tsw\t$0,(%0)\n\t" - "subu\t%1,%1,1\n\t" - "bne\t$0,%1,1b\n\t" - "addiu\t%0,%0,1\n\t" - ".set\treorder" - :"=r" (dummy), - "=r" (dummy) - :"0" ((long) empty_bad_page), - "1" (PTRS_PER_PAGE)); - - return pte_mkdirty(mk_pte((unsigned long) empty_bad_page, PAGE_SHARED)); -#endif } - unsigned long __zero_page(void) { extern char empty_zero_page[PAGE_SIZE]; @@ -106,7 +67,8 @@ printk("Mem-info:\n"); show_free_areas(); printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); - i = high_memory >> PAGE_SHIFT; + /*i = high_memory >> PAGE_SHIFT;*/ + i = MAP_NR(high_memory); while (i-- > 0) { total++; if (PageReserved(mem_map+i)) @@ -137,39 +99,6 @@ */ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem) { -#if 0 - pgd_t * pg_dir; - pte_t * pg_table; - unsigned long tmp; - unsigned long address; - - start_mem = PAGE_ALIGN(start_mem); - address = 0; - pg_dir = swapper_pg_dir; - while (address < end_mem) { - if (pgd_none(pg_dir[0])) { - pgd_set(pg_dir, (pte_t *) start_mem); - start_mem += PAGE_SIZE; - } - /* - * also map it in at 0x00000000 for init - */ - pg_table = (pte_t *) pgd_page(pg_dir[0]); - pgd_set(pg_dir, pg_table); - pg_dir++; - for (tmp = 0 ; tmp < PTRS_PER_PAGE ; tmp++,pg_table++) { - if (address < end_mem) - *pg_table = mk_pte(address, PAGE_SHARED); - else - pte_clear(pg_table); - address += PAGE_SIZE; - } - } -#if KERNELBASE == KSEG0 - cacheflush(); -#endif - invalidate(); -#endif return free_area_init(start_mem, end_mem); } @@ -186,9 +115,6 @@ /* mark usable pages in the mem_map[] */ start_mem = PAGE_ALIGN(start_mem); -#if 0 -_printk("Mem init - Start: %x, End: %x\n", start_mem, high_memory); -#endif for (tmp = KERNELBASE ; tmp < high_memory ; tmp += PAGE_SIZE) { if (tmp < start_mem) @@ -239,28 +165,21 @@ return; } -/* Kernel MMU setup & lowest level hardware support */ - -/* Hardwired MMU segments */ - -/* Segment 0x8XXXXXXX, 0xCXXXXXXX always mapped (for I/O) */ -/* Segment 0x9XXXXXXX mapped during init */ - BAT BAT0 = { { 0x80000000>>17, /* bepi */ BL_256M, /* bl */ - 1, /* vs */ - 1, /* vp */ + 1, /* vs -- supervisor mode valid */ + 1, /* vp -- user mode valid */ }, { 0x80000000>>17, /* brpn */ - 1, /* w */ - 1, /* i (cache disabled) */ - 0, /* m */ - 1, /* g */ - BPP_RW /* pp */ + 1, /* write-through */ + 1, /* cache-inhibited */ + 0, /* memory coherence */ + 1, /* guarded */ + BPP_RW /* protection */ } }; BAT BAT1 = @@ -283,15 +202,15 @@ BAT BAT2 = { { - 0x00000000>>17, /* bepi */ - BL_256M, /* bl */ - 0, /* vs */ + 0x90000000>>17, /* bepi */ + BL_16M, /* this should be set to amount of phys ram */ + 1, /* vs */ 0, /* vp */ }, { 0x00000000>>17, /* brpn */ - 1, /* w */ - 1, /* i (cache disabled) */ + 0, /* w */ + 0, /* i */ 0, /* m */ 0, /* g */ BPP_RW /* pp */ @@ -318,13 +237,13 @@ { /* 0x9XXXXXXX -> 0x0XXXXXXX */ { 0x90000000>>17, /* bepi */ - BL_16M, /* bl */ + BL_256M, /* bl */ 1, /* vs */ 1, /* vp */ }, { 0x00000000>>17, /* brpn */ - 0, /* w */ + 1, /* w */ 0, /* i (cache enabled) */ 0, /* m */ 0, /* g */ @@ -406,9 +325,9 @@ { int i, p; SEGREG *segs; - _printk("MMU init - started\n"); + printk("MMU init - started\n"); find_end_of_memory(); - _printk(" Start at 0x%08X, End at 0x%08X, Hash at 0x%08X\n", _start, _end, Hash); + printk(" Start at 0x%08X, End at 0x%08X, Hash at 0x%08X\n", _start, _end, Hash); _SDR1 = ((unsigned long)Hash & 0x00FFFFFF) | Hash_mask; p = (int)mmu_pages; p = (p + (MMU_PAGE_SIZE-1)) & ~(MMU_PAGE_SIZE-1); @@ -459,7 +378,7 @@ /* Clear all DRAM not explicitly used by kernel */ bzero(_end, (unsigned long)end_of_DRAM-(unsigned long)_end); #endif - _printk("MMU init - done!\n"); + printk("MMU init - done!\n"); } pte * @@ -470,7 +389,7 @@ { bzero((char *)pg, MMU_PAGE_SIZE); } - _printk("MMU Allocate Page at %08X\n", pg); + printk("MMU Allocate Page at %08X\n", pg); return(pg); } @@ -587,7 +506,6 @@ { printk(" V: %d, VSID: %05x, H: %d, RPN: %04x, R: %d, C: %d, PP: %x\n", _pte->v, _pte->vsid, _pte->h, _pte->rpn, _pte->r, _pte->c, _pte->pp); } -cnpause(); printk("Last mappings:\n"); for (i = 0; i < NUM_MAPPINGS; i++) { @@ -597,14 +515,13 @@ last_mappings[next_mapping].task); if (++next_mapping == NUM_MAPPINGS) next_mapping = 0; } -cnpause(); _panic("Hash table full!\n"); } slot = empty; } found_it: #if 0 -_printk("Map VA: %08X, Slot: %08X[%08X/%08X], H: %d\n", va, slot, slot0, slot1, h); +printk("Map VA: %08X, Slot: %08X[%08X/%08X], H: %d\n", va, slot, slot0, slot1, h); #endif _tlbie(va); /* Clear TLB */ if (pg) @@ -1007,7 +924,7 @@ hash &= 0x3FF | (Hash_mask << 10); hash *= 8; /* Eight entries / hash bucket */ _pte = &Hash[hash]; - dump_buf(_pte, 64); +/* dump_buf(_pte, 64);*/ for (i = 0; i < 8; i++, _pte++) { if (_pte->v && _pte->vsid == vsid && _pte->h == _h && _pte->api == api) @@ -1025,7 +942,6 @@ } } found_it: - cnpause(); } flush_cache_all() @@ -1039,3 +955,4 @@ flush_tlb_page() {} flush_tlb_range() {} flush_page_to_ram() {} + diff -ur --new-file old/linux/arch/ppc/mm/mmu.h new/linux/arch/ppc/mm/mmu.h --- old/linux/arch/ppc/mm/mmu.h Mon May 27 11:00:59 1996 +++ new/linux/arch/ppc/mm/mmu.h Thu Jan 1 01:00:00 1970 @@ -1,160 +0,0 @@ -/* - * PowerPC memory management structures - */ - -#ifndef _PPC_MMU_H_ -#define _PPC_MMU_H_ - -/* Hardware Page Table Entry */ - -typedef struct _PTE - { - unsigned long v:1; /* Entry is valid */ - unsigned long vsid:24; /* Virtual segment identifier */ - unsigned long h:1; /* Hash algorithm indicator */ - unsigned long api:6; /* Abbreviated page index */ - unsigned long rpn:20; /* Real (physical) page number */ - unsigned long :3; /* Unused */ - unsigned long r:1; /* Referenced */ - unsigned long c:1; /* Changed */ - unsigned long w:1; /* Write-thru cache mode */ - unsigned long i:1; /* Cache inhibited */ - unsigned long m:1; /* Memory coherence */ - unsigned long g:1; /* Guarded */ - unsigned long :1; /* Unused */ - unsigned long pp:2; /* Page protection */ - } PTE; - -/* Values for PP (assumes Ks=0, Kp=1) */ -#define PP_RWXX 0 /* Supervisor read/write, User none */ -#define PP_RWRX 1 /* Supervisor read/write, User read */ -#define PP_RWRW 2 /* Supervisor read/write, User read/write */ -#define PP_RXRX 3 /* Supervisor read, User read */ - -/* Segment Register */ - -typedef struct _SEGREG - { - unsigned long t:1; /* Normal or I/O type */ - unsigned long ks:1; /* Supervisor 'key' (normally 0) */ - unsigned long kp:1; /* User 'key' (normally 1) */ - unsigned long n:1; /* No-execute */ - unsigned long :4; /* Unused */ - unsigned long vsid:24; /* Virtual Segment Identifier */ - } SEGREG; - -/* Block Address Translation (BAT) Registers */ - -typedef struct _BATU /* Upper part of BAT */ - { - unsigned long bepi:15; /* Effective page index (virtual address) */ - unsigned long :4; /* Unused */ - unsigned long bl:11; /* Block size mask */ - unsigned long vs:1; /* Supervisor valid */ - unsigned long vp:1; /* User valid */ - } BATU; - -typedef struct _BATL /* Lower part of BAT */ - { - unsigned long brpn:15; /* Real page index (physical address) */ - unsigned long :10; /* Unused */ - unsigned long w:1; /* Write-thru cache */ - unsigned long i:1; /* Cache inhibit */ - unsigned long m:1; /* Memory coherence */ - unsigned long g:1; /* Guarded (MBZ) */ - unsigned long :1; /* Unused */ - unsigned long pp:2; /* Page access protections */ - } BATL; - -typedef struct _BAT - { - BATU batu; /* Upper register */ - BATL batl; /* Lower register */ - } BAT; - -/* Block size masks */ -#define BL_128K 0x000 -#define BL_256K 0x001 -#define BL_512K 0x003 -#define BL_1M 0x007 -#define BL_2M 0x00F -#define BL_4M 0x01F -#define BL_8M 0x03F -#define BL_16M 0x07F -#define BL_32M 0x0FF -#define BL_64M 0x1FF -#define BL_128M 0x3FF -#define BL_256M 0x7FF - -/* BAT Access Protection */ -#define BPP_XX 0x00 /* No access */ -#define BPP_RX 0x01 /* Read only */ -#define BPP_RW 0x02 /* Read/write */ - -/* - * Simulated two-level MMU. This structure is used by the kernel - * to keep track of MMU mappings and is used to update/maintain - * the hardware HASH table which is really a cache of mappings. - * - * The simulated structures mimic the hardware available on other - * platforms, notably the 80x86 and 680x0. - */ - -typedef struct _pte - { - unsigned long page_num:20; - unsigned long unused:6; - unsigned long acc:3; /* Read/write/execute permissions */ - unsigned long r:1; /* Page has been referenced */ - unsigned long m:1; /* Page has been modified */ - unsigned long v:1; /* Entry is valid */ - } pte; - -#define ACC_Rxx 0x04 -#define ACC_xWx 0x02 -#define ACC_xxX 0x01 -#define ACC_RWX (ACC_Rxx|ACC_xWx|ACC_xxX) - -#define PD_SHIFT (10+12) /* Page directory */ -#define PD_MASK 0x02FF -#define PT_SHIFT (12) /* Page Table */ -#define PT_MASK 0x02FF -#define PG_SHIFT (12) /* Page Entry */ - - -/* MMU context */ - -typedef struct _MMU_context - { - SEGREG segs[16]; /* Segment registers */ - pte **pmap; /* Two-level page-map structure */ - } MMU_context; - -#if 0 -BAT ibat[4]; /* Instruction BAT images */ -BAT dbat[4]; /* Data BAT images */ -PTE *hash_table; /* Hardware hashed page table */ -int hash_table_size; -int hash_table_mask; -unsigned long sdr; /* Hardware image of SDR */ -#endif - -/* Used to set up SDR register */ -#define HASH_TABLE_SIZE_64K 0x00010000 -#define HASH_TABLE_SIZE_128K 0x00020000 -#define HASH_TABLE_SIZE_256K 0x00040000 -#define HASH_TABLE_SIZE_512K 0x00080000 -#define HASH_TABLE_SIZE_1M 0x00100000 -#define HASH_TABLE_SIZE_2M 0x00200000 -#define HASH_TABLE_SIZE_4M 0x00400000 -#define HASH_TABLE_MASK_64K 0x000 -#define HASH_TABLE_MASK_128K 0x001 -#define HASH_TABLE_MASK_256K 0x003 -#define HASH_TABLE_MASK_512K 0x007 -#define HASH_TABLE_MASK_1M 0x00F -#define HASH_TABLE_MASK_2M 0x01F -#define HASH_TABLE_MASK_4M 0x03F - -#define MMU_PAGE_SIZE 4096 - -#endif diff -ur --new-file old/linux/drivers/atm/Makefile new/linux/drivers/atm/Makefile --- old/linux/drivers/atm/Makefile Thu Aug 29 16:32:43 1996 +++ new/linux/drivers/atm/Makefile Thu Aug 29 16:33:30 1996 @@ -6,15 +6,24 @@ L_TARGET := atm.a L_OBJS := atmdev_init.o M_OBJS := +MOD_LIST_NAME := ATM_MODULES include ../../.config ifeq ($(CONFIG_ATM_ENI),y) L_OBJS += eni.o suni.o +else + ifeq ($(CONFIG_ATM_ENI),m) + M_OBJS += eni.o suni.o + endif endif ifeq ($(CONFIG_ATM_ZATM),y) L_OBJS += zatm.o uPD98402.o +else + ifeq ($(CONFIG_ATM_ZATM),m) + M_OBJS += zatm.o uPD98402.o + endif endif ifeq ($(CONFIG_ATM_TNETA1570),y) diff -ur --new-file old/linux/drivers/atm/eni.c new/linux/drivers/atm/eni.c --- old/linux/drivers/atm/eni.c Thu Aug 29 16:32:43 1996 +++ new/linux/drivers/atm/eni.c Thu Aug 29 16:33:30 1996 @@ -1935,7 +1935,7 @@ int init_module(void) { if (!eni_detect()) { - printk(KERN_ERROR DEV_LABEL ": no adapter found\n"); + printk(KERN_ERR DEV_LABEL ": no adapter found\n"); return -ENXIO; } MOD_INC_USE_COUNT; diff -ur --new-file old/linux/drivers/atm/suni.c new/linux/drivers/atm/suni.c --- old/linux/drivers/atm/suni.c Thu Aug 29 16:32:43 1996 +++ new/linux/drivers/atm/suni.c Thu Aug 29 16:33:30 1996 @@ -3,6 +3,8 @@ /* Written 1995,1996 by Werner Almesberger, EPFL LRC */ +#include +#include #include #include #include @@ -269,3 +271,28 @@ dev->phy = &suni_ops; return 0; } + + +#ifdef MODULE + +static struct symbol_table suni_syms = { +#include + X(suni_init), +#include +}; + + +int init_module(void) +{ + if (register_symtab(&suni_syms)) return -EIO; + MOD_INC_USE_COUNT; + return 0; +} + + +void cleanup_module(void) +{ + /* Nay */ +} + +#endif diff -ur --new-file old/linux/drivers/atm/uPD98402.c new/linux/drivers/atm/uPD98402.c --- old/linux/drivers/atm/uPD98402.c Thu Aug 29 16:32:43 1996 +++ new/linux/drivers/atm/uPD98402.c Thu Aug 29 16:33:31 1996 @@ -3,6 +3,8 @@ /* Written 1995,1996 by Werner Almesberger, EPFL LRC */ +#include +#include #include /* for jiffies */ #include #include @@ -199,3 +201,28 @@ dev->phy = &uPD98402_ops; return 0; } + + +#ifdef MODULE + +static struct symbol_table uPD98402_syms = { +#include + X(uPD98402_init), +#include +}; + + +int init_module(void) +{ + if (register_symtab(&uPD98402_syms)) return -EIO; + MOD_INC_USE_COUNT; + return 0; +} + + +void cleanup_module(void) +{ + /* Nay */ +} + +#endif diff -ur --new-file old/linux/drivers/atm/zatm.c new/linux/drivers/atm/zatm.c --- old/linux/drivers/atm/zatm.c Thu Aug 29 16:32:43 1996 +++ new/linux/drivers/atm/zatm.c Thu Aug 29 16:33:31 1996 @@ -1640,7 +1640,7 @@ int init_module(void) { if (!zatm_detect()) { - printk(KERN_ERROR DEV_LABEL ": no adapter found\n"); + printk(KERN_ERR DEV_LABEL ": no adapter found\n"); return -ENXIO; } MOD_INC_USE_COUNT; diff -ur --new-file old/linux/drivers/block/Config.in new/linux/drivers/block/Config.in --- old/linux/drivers/block/Config.in Wed Jun 5 11:52:58 1996 +++ new/linux/drivers/block/Config.in Mon Aug 5 07:12:25 1996 @@ -15,14 +15,17 @@ bool ' Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE bool ' Support removable IDE interfaces (PCMCIA)' CONFIG_BLK_DEV_IDE_PCMCIA bool ' CMD640 chipset bugfix/support' CONFIG_BLK_DEV_CMD640 + if [ "$CONFIG_BLK_DEV_CMD640" = "y" ]; then + bool ' CMD640 enhanced support' CONFIG_BLK_DEV_CMD640_ENHANCED + fi if [ "$CONFIG_PCI" = "y" ]; then - bool ' Intel 430FX (Triton) chipset DMA support' CONFIG_BLK_DEV_TRITON bool ' RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 + bool ' Intel 82371 PIIX (Triton I/II) DMA support' CONFIG_BLK_DEV_TRITON fi bool ' Other IDE chipset support' CONFIG_IDE_CHIPSETS if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then comment 'Note: most of these also require special kernel boot parameters' - bool ' ALI M1439/M1445 support' CONFIG_BLK_DEV_ALI14XX + bool ' ALI M14xx support' CONFIG_BLK_DEV_ALI14XX bool ' DTC-2278 support' CONFIG_BLK_DEV_DTC2278 bool ' Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then @@ -50,6 +53,8 @@ if [ "$CONFIG_BLK_DEV_HD_IDE" = "y" -o "$CONFIG_BLK_DEV_HD_ONLY" = "y" ]; then define_bool CONFIG_BLK_DEV_HD y +else + define_bool CONFIG_BLK_DEV_HD n fi endmenu diff -ur --new-file old/linux/drivers/block/Makefile new/linux/drivers/block/Makefile --- old/linux/drivers/block/Makefile Sun May 5 08:09:40 1996 +++ new/linux/drivers/block/Makefile Wed Aug 7 11:31:22 1996 @@ -10,13 +10,13 @@ # # -# Note : at this point, these files are compiled on all systems. +# Note : at this point, these files are compiled on all systems. # In the future, some of these should be built conditionally. # L_TARGET := block.a -L_OBJS := ll_rw_blk.o genhd.o +L_OBJS := ll_rw_blk.o genhd.o M_OBJS := MOD_LIST_NAME := BLOCK_MODULES LX_OBJS := diff -ur --new-file old/linux/drivers/block/README.md new/linux/drivers/block/README.md --- old/linux/drivers/block/README.md Mon Feb 26 12:51:45 1996 +++ new/linux/drivers/block/README.md Tue Jun 11 12:00:11 1996 @@ -1,4 +1,4 @@ Tools that manage md devices can be found at sweet-smoke.ufr-info-p7.ibp.fr -in public/Linux/md034.tar.gz. +in public/Linux/md035.tar.gz. Marc ZYNGIER diff -ur --new-file old/linux/drivers/block/ali14xx.c new/linux/drivers/block/ali14xx.c --- old/linux/drivers/block/ali14xx.c Mon Feb 12 06:04:02 1996 +++ new/linux/drivers/block/ali14xx.c Mon Aug 5 07:12:25 1996 @@ -7,6 +7,8 @@ /* * ALI M14xx chipset EIDE controller * + * Works for ALI M1439/1443/1445/1487/1489 chipsets. + * * Adapted from code developed by derekn@vw.ece.cmu.edu. -ml * Derek's notes follow: * @@ -23,6 +25,16 @@ * * Derek Noonburg (derekn@ece.cmu.edu) * 95-sep-26 + * + * Update 96-jul-13: + * + * I've since upgraded to two disks and a CD-ROM, with no trouble, and + * I've also heard from several others who have used it successfully. + * This driver appears to work with both the 1443/1445 and the 1487/1489 + * chipsets. I've added support for PIO mode 4 for the 1487. This + * seems to work just fine on the 1443 also, although I'm not sure it's + * advertised as supporting mode 4. (I've been running a WDC AC21200 in + * mode 4 for a while now with no trouble.) -Derek */ #undef REALLY_SLOW_IO /* most systems can safely undef this */ @@ -39,20 +51,6 @@ #include "ide.h" #include "ide_modes.h" -/* - * This should be set to the system's local bus (PCI or VLB) speed, - * e.g., 33 for a 486DX33 or 486DX2/66. Legal values are anything - * from 25 to 50. Setting this too *low* will make the EIDE - * controller unable to communicate with the disks. - * - * I suggest using a default of 50, since it should work ok with any - * system. (Low values cause problems because it multiplies by bus speed - * to get cycles, and thus gets a too-small cycle count and tries to - * access the disks too fast. I tried this once under DOS and it locked - * up the system.) -- derekn@vw.ece.cmu.edu - */ -#define ALI_14xx_BUS_SPEED 50 /* PCI / VLB bus speed */ - /* port addresses for auto-detection */ #define ALI_NUM_PORTS 4 static int ports[ALI_NUM_PORTS] = {0x074, 0x0f4, 0x034, 0x0e4}; @@ -70,13 +68,7 @@ {0x35, 0x03}, {0x00, 0x00} }; -/* default timing parameters for each PIO mode */ -static struct { int time1, time2; } timeTab[4] = { - {600, 165}, /* PIO 0 */ - {383, 125}, /* PIO 1 */ - {240, 100}, /* PIO 2 */ - {180, 80} /* PIO 3 */ -}; +#define ALI_MAX_PIO 4 /* timing parameter registers for each drive */ static struct { byte reg1, reg2, reg3, reg4; } regTab[4] = { @@ -120,27 +112,20 @@ static void ali14xx_tune_drive (ide_drive_t *drive, byte pio) { int driveNum; - int time1, time2, time1a; + int time1, time2; byte param1, param2, param3, param4; - struct hd_driveid *id = drive->id; unsigned long flags; + ide_pio_data_t d; + int bus_speed = ide_system_bus_speed(); - if (pio == 255) - pio = ide_get_best_pio_mode(drive); - if (pio > 3) - pio = 3; + pio = ide_get_best_pio_mode(drive, pio, ALI_MAX_PIO, &d); /* calculate timing, according to PIO mode */ - time1 = timeTab[pio].time1; - time2 = timeTab[pio].time2; - if (pio == 3) { - time1a = (id->capability & 0x08) ? id->eide_pio_iordy : id->eide_pio; - if (time1a != 0 && time1a < time1) - time1 = time1a; - } - param3 = param1 = (time2 * ALI_14xx_BUS_SPEED + 999) / 1000; - param4 = param2 = (time1 * ALI_14xx_BUS_SPEED + 999) / 1000 - param1; - if (pio != 3) { + time1 = d.cycle_time; + time2 = ide_pio_timings[pio].active_time; + param3 = param1 = (time2 * bus_speed + 999) / 1000; + param4 = param2 = (time1 * bus_speed + 999) / 1000 - param1; + if (pio < 3) { param3 += 8; param4 += 8; } diff -ur --new-file old/linux/drivers/block/cmd640.c new/linux/drivers/block/cmd640.c --- old/linux/drivers/block/cmd640.c Fri May 3 10:07:23 1996 +++ new/linux/drivers/block/cmd640.c Tue Aug 13 07:40:32 1996 @@ -1,54 +1,104 @@ /* - * linux/drivers/block/cmd640.c Version 0.09 Mar 19, 1996 + * linux/drivers/block/cmd640.c Version 1.01 Aug 12, 1996 * * Copyright (C) 1995-1996 Linus Torvalds & authors (see below) */ /* - * Principal Author/Maintainer: abramov@cecmow.enet.dec.com (Igor Abramov) + * Original author: abramov@cecmow.enet.dec.com (Igor Abramov) + * + * Maintained by: mlord@pobox.com (Mark Lord) + * with fanatical support from a legion of hackers! * * This file provides support for the advanced features and bugs * of IDE interfaces using the CMD Technologies 0640 IDE interface chip. * + * These chips are basically fucked by design, and getting this driver + * to work on every motherboard design that uses this screwed chip seems + * bloody well impossible. However, we're still trying. + * + * Version 0.97 worked for everybody. + * + * User feedback is essential. Many thanks to the beta test team: + * + * A.Hartgers@stud.tue.nl, JZDQC@CUNYVM.CUNY.edu, abramov@cecmow.enet.dec.com, + * bardj@utopia.ppp.sn.no, bart@gaga.tue.nl, bbol001@cs.auckland.ac.nz, + * chrisc@dbass.demon.co.uk, dalecki@namu26.Num.Math.Uni-Goettingen.de, + * derekn@vw.ece.cmu.edu, florian@btp2x3.phy.uni-bayreuth.de, + * flynn@dei.unipd.it, gadio@netvision.net.il, godzilla@futuris.net, + * j@pobox.com, jkemp1@mises.uni-paderborn.de, jtoppe@hiwaay.net, + * kerouac@ssnet.com, meskes@informatik.rwth-aachen.de, hzoli@cs.elte.hu, + * peter@udgaard.isgtec.com, phil@tazenda.demon.co.uk, roadcapw@cfw.com, + * s0033las@sun10.vsz.bme.hu, schaffer@tam.cornell.edu, sjd@slip.net, + * steve@ei.org, ulrpeg@bigcomm.gun.de, ism@tardis.ed.ac.uk, mack@cray.com + * liug@mama.indstate.edu, and others. + * * Version 0.01 Initial version, hacked out of ide.c, * and #include'd rather than compiled separately. * This will get cleaned up in a subsequent release. * - * Version 0.02 Fixes for vlb initialization code, enable - * read-ahead for versions 'B' and 'C' of chip by - * default, some code cleanup. + * Version 0.02 Fixes for vlb initialization code, enable prefetch + * for versions 'B' and 'C' of chip by default, + * some code cleanup. * * Version 0.03 Added reset of secondary interface, * and black list for devices which are not compatible - * with read ahead mode. Separate function for setting - * readahead is added, possibly it will be called some + * with prefetch mode. Separate function for setting + * prefetch is added, possibly it will be called some * day from ioctl processing code. - * - * Version 0.04 Now configs/compiles separate from ide.c -ml + * + * Version 0.04 Now configs/compiles separate from ide.c * * Version 0.05 Major rewrite of interface timing code. * Added new function cmd640_set_mode to set PIO mode * from ioctl call. New drives added to black list. * - * Version 0.06 More code cleanup. Readahead is enabled only for - * detected hard drives, not included in readahead + * Version 0.06 More code cleanup. Prefetch is enabled only for + * detected hard drives, not included in prefetch * black list. - * + * * Version 0.07 Changed to more conservative drive tuning policy. - * Unknown drives, which report PIO < 4 are set to + * Unknown drives, which report PIO < 4 are set to * (reported_PIO - 1) if it is supported, or to PIO0. * List of known drives extended by info provided by * CMD at their ftp site. * - * Version 0.08 Added autotune/noautotune support. -ml + * Version 0.08 Added autotune/noautotune support. * - * Version 0.09 Try to be smarter about 2nd port enabling. -ml - * Version 0.10 Be nice and don't reset 2nd port. -ml - * + * Version 0.09 Try to be smarter about 2nd port enabling. + * Version 0.10 Be nice and don't reset 2nd port. + * Version 0.11 Try to handle more wierd situations. + * + * Version 0.12 Lots of bug fixes from Laszlo Peter + * irq unmasking disabled for reliability. + * try to be even smarter about the second port. + * tidy up source code formatting. + * Version 0.13 permit irq unmasking again. + * Version 0.90 massive code cleanup, some bugs fixed. + * defaults all drives to PIO mode0, prefetch off. + * autotune is OFF by default, with compile time flag. + * prefetch can be turned OFF/ON using "hdparm -p8/-p9" + * (requires hdparm-3.1 or newer) + * Version 0.91 first release to linux-kernel list. + * Version 0.92 move initial reg dump to separate callable function + * change "readahead" to "prefetch" to avoid confusion + * Version 0.95 respect original BIOS timings unless autotuning. + * tons of code cleanup and rearrangement. + * added CONFIG_BLK_DEV_CMD640_ENHANCED option + * prevent use of unmask when prefetch is on + * Version 0.96 prevent use of io_32bit when prefetch is off + * Version 0.97 fix VLB secondary interface for sjd@slip.net + * other minor tune-ups: 0.96 was very good. + * Version 0.98 ignore PCI version when disabled by BIOS + * Version 0.99 display setup/active/recovery clocks with PIO mode + * Version 1.00 Mmm.. cannot depend on PCMD_ENA in all systems + * Version 1.01 slow/fast devsel can be selected with "hdparm -p6/-p7" + * ("fast" is necessary for 32bit I/O in some systems) */ #undef REALLY_SLOW_IO /* most systems can safely undef this */ +#include #include #include #include @@ -61,6 +111,9 @@ #include "ide.h" #include "ide_modes.h" +/* + * This flag is set in ide.c by the parameter: ide0=cmd640_vlb + */ int cmd640_vlb = 0; /* @@ -70,6 +123,7 @@ #define VID 0x00 #define DID 0x02 #define PCMD 0x04 +#define PCMD_ENA 0x01 #define PSTTS 0x06 #define REVID 0x08 #define PROGIF 0x09 @@ -101,69 +155,97 @@ #define ARTTIM1 0x55 #define DRWTIM1 0x56 #define ARTTIM23 0x57 -#define DIS_RA2 0x04 -#define DIS_RA3 0x08 +#define ARTTIM23_DIS_RA2 0x04 +#define ARTTIM23_DIS_RA3 0x08 #define DRWTIM23 0x58 #define BRST 0x59 -static ide_tuneproc_t cmd640_tune_drive; +/* + * Registers and masks for easy access by drive index: + */ +static byte prefetch_regs[4] = {CNTRL, CNTRL, ARTTIM23, ARTTIM23}; +static byte prefetch_masks[4] = {CNTRL_DIS_RA0, CNTRL_DIS_RA1, ARTTIM23_DIS_RA2, ARTTIM23_DIS_RA3}; + +#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED -/* Interface to access cmd640x registers */ -static void (*put_cmd640_reg)(int reg_no, int val); - byte (*get_cmd640_reg)(int reg_no); +static byte arttim_regs[4] = {ARTTIM0, ARTTIM1, ARTTIM23, ARTTIM23}; +static byte drwtim_regs[4] = {DRWTIM0, DRWTIM1, DRWTIM23, DRWTIM23}; -enum { none, vlb, pci1, pci2 }; -static int bus_type = none; -static int cmd640_chip_version; -static int cmd640_key; -static int bus_speed; /* MHz */ +/* + * Current cmd640 timing values for each drive. + * The defaults for each are the slowest possible timings. + */ +static byte setup_counts[4] = {4, 4, 4, 4}; /* Address setup count (in clocks) */ +static byte active_counts[4] = {16, 16, 16, 16}; /* Active count (encoded) */ +static byte recovery_counts[4] = {16, 16, 16, 16}; /* Recovery count (encoded) */ + +#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ /* - * For some unknown reasons pcibios functions which read and write registers - * do not always work with cmd640. We use direct IO instead. + * These are initialized to point at the devices we control + */ +static ide_hwif_t *cmd_hwif0, *cmd_hwif1; +static ide_drive_t *cmd_drives[4]; + +/* + * Interface to access cmd640x registers + */ +static unsigned int cmd640_key; +static void (*put_cmd640_reg)(unsigned short reg, byte val); +static byte (*get_cmd640_reg)(unsigned short reg); + +/* + * This is read from the CFR reg, and is used in several places. + */ +static unsigned int cmd640_chip_version; + +/* + * The CMD640x chip does not support DWORD config write cycles, but some + * of the BIOSes use them to implement the config services. + * Therefore, we must use direct IO instead. */ /* PCI method 1 access */ -static void put_cmd640_reg_pci1(int reg_no, int val) +static void put_cmd640_reg_pci1 (unsigned short reg, byte val) { unsigned long flags; save_flags(flags); cli(); - outl_p((reg_no & 0xfc) | cmd640_key, 0xcf8); - outb_p(val, (reg_no & 3) + 0xcfc); + outl_p((reg & 0xfc) | cmd640_key, 0xcf8); + outb_p(val, (reg & 3) | 0xcfc); restore_flags(flags); } -static byte get_cmd640_reg_pci1(int reg_no) +static byte get_cmd640_reg_pci1 (unsigned short reg) { byte b; unsigned long flags; save_flags(flags); cli(); - outl_p((reg_no & 0xfc) | cmd640_key, 0xcf8); - b = inb_p(0xcfc + (reg_no & 3)); + outl_p((reg & 0xfc) | cmd640_key, 0xcf8); + b = inb_p((reg & 3) | 0xcfc); restore_flags(flags); return b; } /* PCI method 2 access (from CMD datasheet) */ -static void put_cmd640_reg_pci2(int reg_no, int val) +static void put_cmd640_reg_pci2 (unsigned short reg, byte val) { unsigned long flags; save_flags(flags); cli(); outb_p(0x10, 0xcf8); - outb_p(val, cmd640_key + reg_no); + outb_p(val, cmd640_key + reg); outb_p(0, 0xcf8); restore_flags(flags); } -static byte get_cmd640_reg_pci2(int reg_no) +static byte get_cmd640_reg_pci2 (unsigned short reg) { byte b; unsigned long flags; @@ -171,7 +253,7 @@ save_flags(flags); cli(); outb_p(0x10, 0xcf8); - b = inb_p(cmd640_key + reg_no); + b = inb_p(cmd640_key + reg); outb_p(0, 0xcf8); restore_flags(flags); return b; @@ -179,48 +261,57 @@ /* VLB access */ -static void put_cmd640_reg_vlb(int reg_no, int val) +static void put_cmd640_reg_vlb (unsigned short reg, byte val) { unsigned long flags; save_flags(flags); cli(); - outb_p(reg_no, cmd640_key + 8); - outb_p(val, cmd640_key + 0xc); + outb_p(reg, cmd640_key); + outb_p(val, cmd640_key + 4); restore_flags(flags); } -static byte get_cmd640_reg_vlb(int reg_no) +static byte get_cmd640_reg_vlb (unsigned short reg) { byte b; unsigned long flags; save_flags(flags); cli(); - outb_p(reg_no, cmd640_key + 8); - b = inb_p(cmd640_key + 0xc); + outb_p(reg, cmd640_key); + b = inb_p(cmd640_key + 4); restore_flags(flags); return b; } +static int match_pci_cmd640_device (void) +{ + const byte ven_dev[4] = {0x95, 0x10, 0x40, 0x06}; + unsigned int i; + for (i = 0; i < 4; i++) { + if (get_cmd640_reg(i) != ven_dev[i]) + return 0; + } +#ifdef STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT + if ((get_cmd640_reg(PCMD) & PCMD_ENA) == 0) { + printk("ide: cmd640 on PCI disabled by BIOS\n"); + return 0; + } +#endif /* STUPIDLY_TRUST_BROKEN_PCMD_ENA_BIT */ + return 1; /* success */ +} + /* * Probe for CMD640x -- pci method 1 */ - -static int probe_for_cmd640_pci1(void) +static int probe_for_cmd640_pci1 (void) { - long id; - int k; - - for (k = 0x80000000; k <= 0x8000f800; k += 0x800) { - outl(k, 0xcf8); - id = inl(0xcfc); - if (id != 0x06401095) - continue; - put_cmd640_reg = put_cmd640_reg_pci1; - get_cmd640_reg = get_cmd640_reg_pci1; - cmd640_key = k; - return 1; + get_cmd640_reg = get_cmd640_reg_pci1; + put_cmd640_reg = put_cmd640_reg_pci1; + for (cmd640_key = 0x80000000; cmd640_key <= 0x8000f800; cmd640_key += 0x800) { + if (match_pci_cmd640_device()) + return 1; /* success */ } return 0; } @@ -228,24 +319,13 @@ /* * Probe for CMD640x -- pci method 2 */ - -static int probe_for_cmd640_pci2(void) +static int probe_for_cmd640_pci2 (void) { - int i; - int v_id; - int d_id; - - for (i = 0xc000; i <= 0xcf00; i += 0x100) { - outb(0x10, 0xcf8); - v_id = inw(i); - d_id = inw(i + 2); - outb(0, 0xcf8); - if (v_id != 0x1095 || d_id != 0x640) - continue; - put_cmd640_reg = put_cmd640_reg_pci2; - get_cmd640_reg = get_cmd640_reg_pci2; - cmd640_key = i; - return 1; + get_cmd640_reg = get_cmd640_reg_pci2; + put_cmd640_reg = put_cmd640_reg_pci2; + for (cmd640_key = 0xc000; cmd640_key <= 0xcf00; cmd640_key += 0x100) { + if (match_pci_cmd640_device()) + return 1; /* success */ } return 0; } @@ -253,511 +333,510 @@ /* * Probe for CMD640x -- vlb */ - -static int probe_for_cmd640_vlb(void) { +static int probe_for_cmd640_vlb (void) +{ byte b; - outb(CFR, 0x178); - b = inb(0x17c); - if (b == 0xff || b == 0 || (b & CFR_AT_VESA_078h)) { - outb(CFR, 0x78); - b = inb(0x7c); - if (b == 0xff || b == 0 || !(b & CFR_AT_VESA_078h)) + get_cmd640_reg = get_cmd640_reg_vlb; + put_cmd640_reg = put_cmd640_reg_vlb; + cmd640_key = 0x178; + b = get_cmd640_reg(CFR); + if (b == 0xff || b == 0x00 || (b & CFR_AT_VESA_078h)) { + cmd640_key = 0x78; + b = get_cmd640_reg(CFR); + if (b == 0xff || b == 0x00 || !(b & CFR_AT_VESA_078h)) return 0; - cmd640_key = 0x70; - } else { - cmd640_key = 0x170; } - put_cmd640_reg = put_cmd640_reg_vlb; - get_cmd640_reg = get_cmd640_reg_vlb; - return 1; + return 1; /* success */ } -#if 0 /* - * Low level reset for controller, actually it has nothing specific for - * CMD640, but I don't know how to use standard reset routine before - * we recognized any drives. + * Returns 1 if an IDE interface/drive exists at 0x170, + * Returns 0 otherwise. */ -static void cmd640_reset_controller(int iface_no) +static int secondary_port_responding (void) { - int retry_count = 600; - int base_port = iface_no ? 0x170 : 0x1f0; - - outb_p(4, base_port + 7); - udelay(5); - outb_p(0, base_port + 7); + unsigned long flags; - do { - udelay(5); - retry_count -= 1; - } while ((inb_p(base_port + 7) & 0x80) && retry_count); + save_flags(flags); + cli(); - if (retry_count == 0) - printk("cmd640: failed to reset controller %d\n", iface_no); + outb_p(0x0a, 0x170 + IDE_SELECT_OFFSET); /* select drive0 */ + udelay(100); + if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x0a) { + outb_p(0x1a, 0x170 + IDE_SELECT_OFFSET); /* select drive1 */ + udelay(100); + if ((inb_p(0x170 + IDE_SELECT_OFFSET) & 0x1f) != 0x1a) { + restore_flags(flags); + return 0; /* nothing responded */ + } + } + restore_flags(flags); + return 1; /* success */ } -#endif /* 0 */ +#ifdef CMD640_DUMP_REGS /* - * Returns 1 if an IDE interface/drive exists at 0x170, - * Returns 0 otherwise. + * Dump out all cmd640 registers. May be called from ide.c */ -int secondary_port_responding (void) +void cmd640_dump_regs (void) { - /* - * Test for hardware at 0x170 (secondary IDE port). - * Leave the enable-bit alone if something responds. - */ - outb_p(0x0a,0x176); /* select drive0 */ - udelay(1); - if (inb_p(0x176) == 0xff) { - outb_p(0x0b,0x176); /* select drive1 */ - udelay(1); - if (inb_p(0x176) == 0xff) - return 0; /* nothing is there */ + unsigned int reg = cmd640_vlb ? 0x50 : 0x00; + + /* Dump current state of chip registers */ + printk("ide: cmd640 internal register dump:"); + for (; reg <= 0x59; reg++) { + if (!(reg & 0x0f)) + printk("\n%04x:", reg); + printk(" %02x", get_cmd640_reg(reg)); } - return 1; /* something is there */ + printk("\n"); } +#endif /* - * Probe for Cmd640x and initialize it if found + * Check whether prefetch is on for a drive, + * and initialize the unmask flags for safe operation. */ - -int ide_probe_for_cmd640x(void) +static void check_prefetch (unsigned int index) { - int second_port_toggled = 0; - byte b; + ide_drive_t *drive = cmd_drives[index]; + byte b = get_cmd640_reg(prefetch_regs[index]); - if (probe_for_cmd640_pci1()) { - bus_type = pci1; - } else if (probe_for_cmd640_pci2()) { - bus_type = pci2; - } else if (cmd640_vlb && probe_for_cmd640_vlb()) { - /* May be remove cmd640_vlb at all, and probe in any case */ - bus_type = vlb; + if (b & prefetch_masks[index]) { /* is prefetch off? */ + drive->no_unmask = 0; + drive->no_io_32bit = 1; + drive->io_32bit = 0; } else { - return 0; - } - - ide_hwifs[0].serialized = 1; /* ensure this *always* gets set */ - ide_hwifs[1].serialized = 1; /* ensure this *always* gets set */ - -#if 0 - /* Dump initial state of chip registers */ - for (b = 0; b != 0xff; b++) { - printk(" %2x%c", get_cmd640_reg(b), - ((b&0xf) == 0xf) ? '\n' : ','); - } -#endif - - /* - * Undocumented magic. (There is no 0x5b port in specs) - */ - - put_cmd640_reg(0x5b, 0xbd); - if (get_cmd640_reg(0x5b) != 0xbd) { - printk("ide: can't initialize cmd640 -- wrong value in 0x5b\n"); - return 0; - } - put_cmd640_reg(0x5b, 0); - - /* - * Documented magic. - */ - - cmd640_chip_version = get_cmd640_reg(CFR) & CFR_DEVREV; - if (cmd640_chip_version == 0) { - printk ("ide: wrong CMD640 version -- 0\n"); - return 0; + drive->no_unmask = 1; + drive->no_io_32bit = 0; + drive->unmask = 0; } +} - /* - * Setup the most conservative timings for all drives, - */ - put_cmd640_reg(ARTTIM0, 0xc0); - put_cmd640_reg(ARTTIM1, 0xc0); - put_cmd640_reg(ARTTIM23, 0xcc); /* 0xc0? */ - - /* - * Set the maximum allowed bus speed (it is safest until we - * find how to detect bus speed) - * Normally PCI bus runs at 33MHz, but often works overclocked to 40 - */ - bus_speed = (bus_type == vlb) ? 50 : 40; - - /* - * Setup Control Register - */ - b = get_cmd640_reg(CNTRL); - - if (!secondary_port_responding()) { - b ^= CNTRL_ENA_2ND; /* toggle the bit */ - second_port_toggled = 1; - } - - /* - * Disable readahead for drives at primary interface - */ - b |= (CNTRL_DIS_RA0 | CNTRL_DIS_RA1); - - put_cmd640_reg(CNTRL, b); - - /* - * Note that we assume that the first interface is at 0x1f0, - * and that the second interface, if enabled, is at 0x170. - */ - ide_hwifs[0].chipset = ide_cmd640; - ide_hwifs[0].tuneproc = &cmd640_tune_drive; - if (ide_hwifs[0].drives[0].autotune == 0) - ide_hwifs[0].drives[0].autotune = 1; - if (ide_hwifs[0].drives[1].autotune == 0) - ide_hwifs[0].drives[1].autotune = 1; - - /* - * Initialize 2nd IDE port, if required - */ - if (secondary_port_responding()) { - ide_hwifs[1].chipset = ide_cmd640; - ide_hwifs[1].tuneproc = &cmd640_tune_drive; - if (ide_hwifs[1].drives[0].autotune == 0) - ide_hwifs[1].drives[0].autotune = 1; - if (ide_hwifs[1].drives[1].autotune == 0) - ide_hwifs[1].drives[1].autotune = 1; - /* disable read-ahead for drives 2 & 3 */ - put_cmd640_reg(ARTTIM23, (DIS_RA2 | DIS_RA3)); +/* + * Figure out which devices we control + */ +static void setup_device_ptrs (void) +{ + unsigned int i; - if (second_port_toggled) { - /* reset PIO timings for drives 2 & 3 */ - put_cmd640_reg(DRWTIM23, 0); + cmd_hwif0 = &ide_hwifs[0]; /* default, if not found below */ + cmd_hwif1 = &ide_hwifs[1]; /* default, if not found below */ + for (i = 0; i < MAX_HWIFS; i++) { + ide_hwif_t *hwif = &ide_hwifs[i]; + if (hwif->chipset == ide_unknown || hwif->chipset == ide_generic) { + if (hwif->io_base == 0x1f0) + cmd_hwif0 = hwif; + else if (hwif->io_base == 0x170) + cmd_hwif1 = hwif; } -#if 0 - /* reset the secondary interface */ - cmd640_reset_controller(1); -#endif } - - printk("ide: buggy CMD640%c interface on ", - 'A' - 1 + cmd640_chip_version); - switch (bus_type) { - case vlb : - printk("vlb (0x%x)", cmd640_key); - break; - case pci1: - printk("pci (0x%x)", cmd640_key); - break; - case pci2: - printk("pci (access method 2) (0x%x)", cmd640_key); - break; - } - -#if 0 - /* reset PIO timings for drives 1 & 2 */ - put_cmd640_reg(CMDTIM, 0); -#endif /* 0 */ - - /* - * Tell everyone what we did to their system - */ - printk("; serialized, secondary port %s\n", second_port_toggled ? "toggled" : "untouched"); - return 1; + cmd_drives[0] = &cmd_hwif0->drives[0]; + cmd_drives[1] = &cmd_hwif0->drives[1]; + cmd_drives[2] = &cmd_hwif1->drives[0]; + cmd_drives[3] = &cmd_hwif1->drives[1]; } -#if 0 /* not used anywhere */ -int cmd640_off(void) { - static int a = 0; - byte b; - - if (bus_type == none || a == 1) - return 0; - a = 1; - b = get_cmd640_reg(CNTRL); - b &= ~CNTRL_ENA_2ND; - put_cmd640_reg(CNTRL, b); - return 1; -} -#endif /* 0 */ +#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED /* - * Sets readahead mode for specific drive - * in the future it could be called from ioctl + * Sets prefetch mode for a drive. */ - -static void set_readahead_mode(int mode, int if_num, int dr_num) +static void set_prefetch_mode (unsigned int index, int mode) { - static int masks[2][2] = - { - {CNTRL_DIS_RA0, CNTRL_DIS_RA1}, - {DIS_RA2, DIS_RA3} - }; - - int port = (if_num == 0) ? CNTRL : ARTTIM23; - int mask = masks[if_num][dr_num]; + ide_drive_t *drive = cmd_drives[index]; + int reg = prefetch_regs[index]; byte b; + unsigned long flags; - b = get_cmd640_reg(port); - if (mode) - b &= ~mask; /* Enable readahead for specific drive */ - else - b |= mask; /* Disable readahead for specific drive */ - put_cmd640_reg(port, b); -} - -static struct readahead_black_list { - const char* name; - int mode; -} drives_ra[] = { - { "QUANTUM LIGHTNING 540A", 0 }, - { "ST3655A", 0 }, - { "SAMSUNG", 0 }, /* Be conservative */ - { NULL, 0 } -}; - -static int strmatch(const char* pattern, const char* name) { - char c1, c2; - - while (1) { - c1 = *pattern++; - c2 = *name++; - if (c1 == 0) { - return 0; - } - if (c1 != c2) - return 1; - } -} - -static int known_drive_readahead(char* name) { - int i; - - for (i = 0; drives_ra[i].name != NULL; i++) { - if (strmatch(drives_ra[i].name, name) == 0) { - return drives_ra[i].mode; - } + save_flags(flags); + cli(); + b = get_cmd640_reg(reg); + if (mode) { /* want prefetch on? */ + drive->no_unmask = 1; + drive->unmask = 0; + drive->no_io_32bit = 0; + b &= ~prefetch_masks[index]; /* enable prefetch */ + } else { + drive->no_unmask = 0; + drive->no_io_32bit = 1; + drive->io_32bit = 0; + b |= prefetch_masks[index]; /* disable prefetch */ } - return -1; + put_cmd640_reg(reg, b); + restore_flags(flags); } -static int arttim[4] = {2, 2, 2, 2}; /* Address setup count (in clocks) */ -static int a_count[4] = {1, 1, 1, 1}; /* Active count (encoded) */ -static int r_count[4] = {1, 1, 1, 1}; /* Recovery count (encoded) */ - /* - * Convert address setup count from number of clocks - * to representation used by controller + * Dump out current drive clocks settings */ - -inline static int pack_arttim(int clocks) +static void display_clocks (unsigned int index) { - if (clocks <= 2) return 0x40; - else if (clocks == 3) return 0x80; - else if (clocks == 4) return 0x00; - else return 0xc0; + byte active_count, recovery_count; + + active_count = active_counts[index]; + if (active_count == 1) + ++active_count; + recovery_count = recovery_counts[index]; + if (active_count > 3 && recovery_count == 1) + ++recovery_count; + if (cmd640_chip_version > 1) + recovery_count += 1; /* cmd640b uses (count + 1)*/ + printk(", clocks=%d/%d/%d\n", setup_counts[index], active_count, recovery_count); } /* * Pack active and recovery counts into single byte representation * used by controller */ - -inline static int pack_counts(int act_count, int rec_count) +inline static byte pack_nibbles (byte upper, byte lower) { - return ((act_count & 0x0f)<<4) | (rec_count & 0x0f); + return ((upper & 0x0f) << 4) | (lower & 0x0f); } -inline int max(int a, int b) { return a > b ? a : b; } -inline int max4(int *p) { return max(p[0], max(p[1], max(p[2], p[3]))); } - /* - * Set timing parameters + * This routine retrieves the initial drive timings from the chipset. */ - -static void cmd640_set_timing(int if_num, int dr_num) +static void retrieve_drive_counts (unsigned int index) { - int b_reg; - int ac, rc, at; + byte b; /* - * Set address setup count and drive read/write timing registers. - * Primary interface has individual count/timing registers for - * each drive. Secondary interface has common set of registers, and - * we should set timings for the slowest drive. + * Get the internal setup timing, and convert to clock count */ - - if (if_num == 0) { - b_reg = dr_num ? ARTTIM1 : ARTTIM0; - at = arttim[dr_num]; - ac = a_count[dr_num]; - rc = r_count[dr_num]; - } else { - b_reg = ARTTIM23; - at = max(arttim[2], arttim[3]); - ac = max(a_count[2], a_count[3]); - rc = max(r_count[2], r_count[3]); + b = get_cmd640_reg(arttim_regs[index]) & ~0x3f; + switch (b) { + case 0x00: b = 4; break; + case 0x80: b = 3; break; + case 0x40: b = 2; break; + default: b = 5; break; } - - put_cmd640_reg(b_reg, pack_arttim(at)); - put_cmd640_reg(b_reg + 1, pack_counts(ac, rc)); + setup_counts[index] = b; /* - * Update CMDTIM (IDE Command Block Timing Register) + * Get the active/recovery counts */ - - ac = max4(r_count); - rc = max4(a_count); - put_cmd640_reg(CMDTIM, pack_counts(ac, rc)); + b = get_cmd640_reg(drwtim_regs[index]); + active_counts[index] = (b >> 4) ? (b >> 4) : 0x10; + recovery_counts[index] = (b & 0x0f) ? (b & 0x0f) : 0x10; } + /* - * Standard timings for PIO modes + * This routine writes the prepared setup/active/recovery counts + * for a drive into the cmd640 chipset registers to active them. */ - -static struct pio_timing { - int mc_time; /* Minimal cycle time (ns) */ - int av_time; /* Address valid to DIOR-/DIOW- setup (ns) */ - int ds_time; /* DIOR data setup (ns) */ -} pio_timings[6] = { - { 70, 165, 600 }, /* PIO Mode 0 */ - { 50, 125, 383 }, /* PIO Mode 1 */ - { 30, 100, 240 }, /* PIO Mode 2 */ - { 30, 80, 180 }, /* PIO Mode 3 */ - { 25, 70, 125 }, /* PIO Mode 4 -- should be 120, not 125 */ - { 20, 50, 100 } /* PIO Mode ? (nonstandard) */ -}; - -static void cmd640_timings_to_clocks(int mc_time, int av_time, int ds_time, - int clock_time, int drv_idx) +static void program_drive_counts (unsigned int index) { - int a, b; + unsigned long flags; + byte setup_count = setup_counts[index]; + byte active_count = active_counts[index]; + byte recovery_count = recovery_counts[index]; - arttim[drv_idx] = (mc_time + clock_time - 1)/clock_time; + /* + * Set up address setup count and drive read/write timing registers. + * Primary interface has individual count/timing registers for + * each drive. Secondary interface has one common set of registers, + * so we merge the timings, using the slowest value for each timing. + */ + if (index > 1) { + unsigned int mate; + if (cmd_drives[mate = index ^ 1]->present) { + if (setup_count < setup_counts[mate]) + setup_count = setup_counts[mate]; + if (active_count < active_counts[mate]) + active_count = active_counts[mate]; + if (recovery_count < recovery_counts[mate]) + recovery_count = recovery_counts[mate]; + } + } - a = (av_time + clock_time - 1)/clock_time; - if (a < 2) - a = 2; - b = (ds_time + clock_time - 1)/clock_time - a; - if (b < 2) - b = 2; - if (b > 0x11) { - a += b - 0x11; - b = 0x11; + /* + * Convert setup_count to internal chipset representation + */ + switch (setup_count) { + case 4: setup_count = 0x00; + case 3: setup_count = 0x80; + case 2: setup_count = 0x40; + default: setup_count = 0xc0; /* case 5 */ } - if (a > 0x10) - a = 0x10; - if (cmd640_chip_version > 1) - b -= 1; - if (b > 0x10) - b = 0x10; - - a_count[drv_idx] = a; - r_count[drv_idx] = b; -} - -static void set_pio_mode(int if_num, int drv_num, int mode_num) { - int p_base; - int i; - - p_base = if_num ? 0x170 : 0x1f0; - outb_p(3, p_base + 1); - outb_p(mode_num | 8, p_base + 2); - outb_p((drv_num | 0xa) << 4, p_base + 6); - outb_p(0xef, p_base + 7); - for (i = 0; (i < 100) && (inb (p_base + 7) & 0x80); i++) - udelay(10000); + + /* + * Now that everything is ready, program the new timings + */ + save_flags (flags); + cli(); + /* + * Program the address_setup clocks into ARTTIM reg, + * and then the active/recovery counts into the DRWTIM reg + * (this converts counts of 16 into counts of zero -- okay). + */ + setup_count |= get_cmd640_reg(arttim_regs[index]) & 0x3f; + put_cmd640_reg(arttim_regs[index], setup_count); + put_cmd640_reg(drwtim_regs[index], pack_nibbles(active_count, recovery_count)); + restore_flags(flags); } /* * Set a specific pio_mode for a drive */ +static void cmd640_set_mode (unsigned int index, byte pio_mode, unsigned int cycle_time) +{ + int setup_time, active_time, recovery_time, clock_time; + byte setup_count, active_count, recovery_count, recovery_count2, cycle_count; + int bus_speed = ide_system_bus_speed(); + + if (pio_mode > 5) + pio_mode = 5; + setup_time = ide_pio_timings[pio_mode].setup_time; + active_time = ide_pio_timings[pio_mode].active_time; + recovery_time = cycle_time - (setup_time + active_time); + clock_time = 1000 / bus_speed; + cycle_count = (cycle_time + clock_time - 1) / clock_time; + + setup_count = (setup_time + clock_time - 1) / clock_time; + + active_count = (active_time + clock_time - 1) / clock_time; + if (active_count < 2) + active_count = 2; /* minimum allowed by cmd640 */ + + recovery_count = (recovery_time + clock_time - 1) / clock_time; + recovery_count2 = cycle_count - (setup_count + active_count); + if (recovery_count2 > recovery_count) + recovery_count = recovery_count2; + if (recovery_count < 2) + recovery_count = 2; /* minimum allowed by cmd640 */ + if (recovery_count > 17) { + active_count += recovery_count - 17; + recovery_count = 17; + } + if (active_count > 16) + active_count = 16; /* maximum allowed by cmd640 */ + if (cmd640_chip_version > 1) + recovery_count -= 1; /* cmd640b uses (count + 1)*/ + if (recovery_count > 16) + recovery_count = 16; /* maximum allowed by cmd640 */ + + setup_counts[index] = setup_count; + active_counts[index] = active_count; + recovery_counts[index] = recovery_count; -static void cmd640_set_mode(ide_drive_t* drive, int pio_mode) { - int interface_number; - int drive_number; - int clock_time; /* ns */ - int mc_time, av_time, ds_time; - - interface_number = HWIF(drive)->index; - drive_number = drive->select.b.unit; - clock_time = 1000/bus_speed; - - mc_time = pio_timings[pio_mode].mc_time; - av_time = pio_timings[pio_mode].av_time; - ds_time = pio_timings[pio_mode].ds_time; - - cmd640_timings_to_clocks(mc_time, av_time, ds_time, clock_time, - interface_number*2 + drive_number); - set_pio_mode(interface_number, drive_number, pio_mode); - cmd640_set_timing(interface_number, drive_number); + /* + * In a perfect world, we might set the drive pio mode here + * (using WIN_SETFEATURE) before continuing. + * + * But we do not, because: + * 1) this is the wrong place to do it (proper is do_special() in ide.c) + * 2) in practice this is rarely, if ever, necessary + */ + program_drive_counts (index); } /* - * Drive PIO mode "autoconfiguration". - * Ideally, this code should *always* call cmd640_set_mode(), but it doesn't. - */ - -static void cmd640_tune_drive(ide_drive_t *drive, byte pio_mode) { - int interface_number; - int drive_number; - int clock_time; /* ns */ - int max_pio; - int mc_time, av_time, ds_time; - struct hd_driveid* id; - int readahead; /* there is a global named read_ahead */ - - if (pio_mode != 255) { - cmd640_set_mode(drive, pio_mode); - return; - } - - interface_number = HWIF(drive)->index; - drive_number = drive->select.b.unit; - clock_time = 1000/bus_speed; - id = drive->id; - if ((max_pio = ide_scan_pio_blacklist(id->model)) != -1) { - ds_time = pio_timings[max_pio].ds_time; + * Drive PIO mode selection: + */ +static void cmd640_tune_drive (ide_drive_t *drive, byte mode_wanted) +{ + byte b; + ide_pio_data_t d; + unsigned int index = 0; + + while (drive != cmd_drives[index]) { + if (++index > 3) { + printk("%s: bad news in cmd640_tune_drive\n", drive->name); + return; + } + } + switch (mode_wanted) { + case 6: /* set fast-devsel off */ + case 7: /* set fast-devsel on */ + mode_wanted &= 1; + b = get_cmd640_reg(CNTRL) & ~0x27; + if (mode_wanted) + b |= 0x27; + put_cmd640_reg(CNTRL, b); + printk("%s: %sabled cmd640 fast host timing (devsel)\n", drive->name, mode_wanted ? "en" : "dis"); + return; + + case 8: /* set prefetch off */ + case 9: /* set prefetch on */ + mode_wanted &= 1; + set_prefetch_mode(index, mode_wanted); + printk("%s: %sabled cmd640 prefetch\n", drive->name, mode_wanted ? "en" : "dis"); + return; + } + + (void) ide_get_best_pio_mode (drive, mode_wanted, 5, &d); + cmd640_set_mode (index, d.pio_mode, d.cycle_time); + + printk ("%s: selected cmd640 PIO mode%d (%dns) %s/IORDY%s", + drive->name, + d.pio_mode, + d.cycle_time, + d.use_iordy ? "w" : "wo", + d.overridden ? " (overriding vendor mode)" : ""); + display_clocks(index); +} + +#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ + +/* + * Probe for a cmd640 chipset, and initialize it if found. Called from ide.c + */ +int ide_probe_for_cmd640x (void) +{ +#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED + int second_port_toggled = 0; +#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ + int second_port_cmd640 = 0; + const char *bus_type, *port2; + unsigned int index; + byte b, cfr; + + if (cmd640_vlb && probe_for_cmd640_vlb()) { + bus_type = "VLB"; + } else { + cmd640_vlb = 0; + if (probe_for_cmd640_pci1()) + bus_type = "PCI (type1)"; + else if (probe_for_cmd640_pci2()) + bus_type = "PCI (type2)"; + else + return 0; + } + /* + * Undocumented magic (there is no 0x5b reg in specs) + */ + put_cmd640_reg(0x5b, 0xbd); + if (get_cmd640_reg(0x5b) != 0xbd) { + printk("ide: cmd640 init failed: wrong value in reg 0x5b\n"); + return 0; + } + put_cmd640_reg(0x5b, 0); + +#ifdef CMD640_DUMP_REGS + CMD640_DUMP_REGS; +#endif + + /* + * Documented magic begins here + */ + cfr = get_cmd640_reg(CFR); + cmd640_chip_version = cfr & CFR_DEVREV; + if (cmd640_chip_version == 0) { + printk ("ide: bad cmd640 revision: %d\n", cmd640_chip_version); + return 0; + } + + /* + * Initialize data for primary port + */ + setup_device_ptrs (); + printk("%s: buggy cmd640%c interface on %s, config=0x%02x\n", + cmd_hwif0->name, 'a' + cmd640_chip_version - 1, bus_type, cfr); + cmd_hwif0->chipset = ide_cmd640; +#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED + cmd_hwif0->tuneproc = &cmd640_tune_drive; +#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ + + /* + * Ensure compatibility by always using the slowest timings + * for access to the drive's command register block, + * and reset the prefetch burstsize to default (512 bytes). + * + * Maybe we need a way to NOT do these on *some* systems? + */ + put_cmd640_reg(CMDTIM, 0); + put_cmd640_reg(BRST, 0x40); + + /* + * Try to enable the secondary interface, if not already enabled + */ + if (cmd_hwif1->noprobe) { + port2 = "not probed"; } else { - max_pio = id->tPIO; - ds_time = pio_timings[max_pio].ds_time; - if (id->field_valid & 2) { - if ((id->capability & 8) && (id->eide_pio_modes & 7)) { - if (id->eide_pio_modes & 4) max_pio = 5; - else if (id->eide_pio_modes & 2) max_pio = 4; - else max_pio = 3; - ds_time = id->eide_pio_iordy; + b = get_cmd640_reg(CNTRL); + if (secondary_port_responding()) { + if ((b & CNTRL_ENA_2ND)) { + second_port_cmd640 = 1; + port2 = "okay"; + } else if (cmd640_vlb) { + second_port_cmd640 = 1; + port2 = "alive"; + } else + port2 = "not cmd640"; + } else { + put_cmd640_reg(CNTRL, b ^ CNTRL_ENA_2ND); /* toggle the bit */ + if (secondary_port_responding()) { + second_port_cmd640 = 1; +#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED + second_port_toggled = 1; +#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ + port2 = "enabled"; } else { - ds_time = id->eide_pio; + put_cmd640_reg(CNTRL, b); /* restore original setting */ + port2 = "not responding"; } - if (ds_time == 0) - ds_time = pio_timings[max_pio].ds_time; } + } + /* + * Initialize data for secondary cmd640 port, if enabled + */ + if (second_port_cmd640) { + cmd_hwif0->serialized = 1; + cmd_hwif1->serialized = 1; + cmd_hwif1->chipset = ide_cmd640; +#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED + cmd_hwif1->tuneproc = &cmd640_tune_drive; +#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ + } + printk("%s: %sserialized, secondary interface %s\n", cmd_hwif1->name, + cmd_hwif0->serialized ? "" : "not ", port2); + + /* + * Establish initial timings/prefetch for all drives. + * Do not unnecessarily disturb any prior BIOS setup of these. + */ + for (index = 0; index < (2 + (second_port_cmd640 << 1)); index++) { + ide_drive_t *drive = cmd_drives[index]; +#ifdef CONFIG_BLK_DEV_CMD640_ENHANCED + if (drive->autotune || ((index > 1) && second_port_toggled)) { + /* + * Reset timing to the slowest speed and turn off prefetch. + * This way, the drive identify code has a better chance. + */ + setup_counts [index] = 4; /* max possible */ + active_counts [index] = 16; /* max possible */ + recovery_counts [index] = 16; /* max possible */ + program_drive_counts (index); + set_prefetch_mode (index, 0); + printk("cmd640: drive%d timings/prefetch cleared\n", index); + } else { + /* + * Record timings/prefetch without changing them. + * This preserves any prior BIOS setup. + */ + retrieve_drive_counts (index); + check_prefetch (index); + printk("cmd640: drive%d timings/prefetch(%s) preserved", + index, drive->no_io_32bit ? "off" : "on"); + display_clocks(index); + } +#else /* - * Conservative "downgrade" + * Set the drive unmask flags to match the prefetch setting */ - if (max_pio < 4 && max_pio != 0) { - max_pio -= 1; - ds_time = pio_timings[max_pio].ds_time; - } + check_prefetch (index); + printk("cmd640: drive%d timings/prefetch(%s) preserved\n", + index, drive->no_io_32bit ? "off" : "on"); +#endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ } - mc_time = pio_timings[max_pio].mc_time; - av_time = pio_timings[max_pio].av_time; - cmd640_timings_to_clocks(mc_time, av_time, ds_time, clock_time, - interface_number*2 + drive_number); - set_pio_mode(interface_number, drive_number, max_pio); - cmd640_set_timing(interface_number, drive_number); - - /* - * Disable (or set) readahead mode - */ - - readahead = 0; - if (cmd640_chip_version > 1) { /* Mmmm.. probably should be > 2 ?? */ - readahead = known_drive_readahead(id->model); - if (readahead == -1) - readahead = 1; /* Mmmm.. probably be 0 ?? */ - set_readahead_mode(readahead, interface_number, drive_number); - } - printk ("Mode and Timing set to PIO%d, Readahead is %s\n", - max_pio, readahead ? "enabled" : "disabled"); +#ifdef CMD640_DUMP_REGS + CMD640_DUMP_REGS; +#endif + return 1; } diff -ur --new-file old/linux/drivers/block/dtc2278.c new/linux/drivers/block/dtc2278.c --- old/linux/drivers/block/dtc2278.c Fri May 3 10:07:23 1996 +++ new/linux/drivers/block/dtc2278.c Mon Aug 5 07:12:25 1996 @@ -41,8 +41,8 @@ * * DTC2278S has only a single IDE interface. * DTC2278D has two IDE interfaces and is otherwise identical to the S version. - * DTC2278E has onboard BIOS, while the others do not. - * DTC2278EB: "works like a charm" -- Kent Bradford + * DTC2278E also has serial ports and a printer port + * DTC2278EB: has onboard BIOS, and "works like a charm" -- Kent Bradford * * There may be a fourth controller type. The S and D versions use the * Winbond chip, and I think the E version does also. @@ -71,8 +71,7 @@ { unsigned long flags; - if (pio == 255) - pio = ide_get_best_pio_mode(drive); + pio = ide_get_best_pio_mode(drive, pio, 4, NULL); if (pio >= 3) { save_flags(flags); @@ -122,6 +121,8 @@ ide_hwifs[0].chipset = ide_dtc2278; ide_hwifs[1].chipset = ide_dtc2278; ide_hwifs[0].tuneproc = &tune_dtc2278; - ide_hwifs[0].no_unmask = 1; - ide_hwifs[1].no_unmask = 1; + ide_hwifs[0].drives[0].no_unmask = 1; + ide_hwifs[0].drives[1].no_unmask = 1; + ide_hwifs[1].drives[0].no_unmask = 1; + ide_hwifs[1].drives[1].no_unmask = 1; } diff -ur --new-file old/linux/drivers/block/floppy.c new/linux/drivers/block/floppy.c --- old/linux/drivers/block/floppy.c Thu May 30 14:56:07 1996 +++ new/linux/drivers/block/floppy.c Thu Aug 8 11:30:42 1996 @@ -155,6 +155,7 @@ #include #include /* CMOS defines */ #include +#include #include #include @@ -1039,6 +1040,7 @@ INT_OFF; fd_disable_dma(); fd_clear_dma_ff(); + fd_cacheflush(raw_cmd->kernel_data, raw_cmd->length); fd_set_dma_mode((raw_cmd->flags & FD_RAW_READ)? DMA_MODE_READ : DMA_MODE_WRITE); fd_set_dma_addr(virt_to_bus(raw_cmd->kernel_data)); @@ -1229,7 +1231,6 @@ /*DPRINT("FIFO enabled\n");*/ } -#ifndef __sparc__ switch (raw_cmd->rate & 0x03) { case 3: dtr = 1000; @@ -1284,7 +1285,6 @@ output_byte(FDCS->spec1 = spec1); output_byte(FDCS->spec2 = spec2); } -#endif } /* fdc_specify */ /* Set the FDC's data transfer rate on behalf of the specified drive. @@ -1926,7 +1926,6 @@ floppy_tq.routine = (void *)(void *) handler; queue_task(&floppy_tq, &tq_timer); - INT_OFF; while(command_status < 2 && NO_SIGNAL){ is_alive("wait_til_done"); @@ -2385,13 +2384,10 @@ if (((unsigned long)buffer) % 512) DPRINT("%p buffer not aligned\n", buffer); #endif - if (CT(COMMAND) == FD_READ) { - fd_cacheflush(dma_buffer, size); + if (CT(COMMAND) == FD_READ) memcpy(buffer, dma_buffer, size); - } else { + else memcpy(dma_buffer, buffer, size); - fd_cacheflush(dma_buffer, size); - } remaining -= size; if (!remaining) break; @@ -2708,6 +2704,7 @@ raw_cmd = & default_raw_cmd; raw_cmd->flags = 0; if (start_motor(redo_fd_request)) return; + disk_change(current_drive); if (test_bit(current_drive, &fake_change) || TESTF(FD_DISK_CHANGED)){ DPRINT("disk absent or changed during operation\n"); @@ -2762,6 +2759,7 @@ static void do_fd_request(void) { + sti(); if (fdc_busy){ /* fdc busy, this new request will be treated when the current one is done */ @@ -2839,9 +2837,6 @@ int ret; ECALL(verify_area(VERIFY_WRITE,param,size)); - fd_cacheflush(address, size); /* is this necessary ??? */ - /* Ralf: Yes; only the l2 cache is completely chipset - controlled */ memcpy_tofs(param,(void *) address, size); return 0; } @@ -2883,7 +2878,7 @@ int i; if (!flag) { - raw_cmd->flags = FD_RAW_FAILURE; + raw_cmd->flags |= FD_RAW_FAILURE; raw_cmd->flags |= FD_RAW_HARDFAILURE; } else { raw_cmd->reply_count = inr; diff -ur --new-file old/linux/drivers/block/genhd.c new/linux/drivers/block/genhd.c --- old/linux/drivers/block/genhd.c Thu Aug 29 16:32:45 1996 +++ new/linux/drivers/block/genhd.c Thu Aug 29 16:33:32 1996 @@ -37,6 +37,7 @@ */ #include +#define SYS_IND(p) get_unaligned(&p->sys_ind) #define NR_SECTS(p) get_unaligned(&p->nr_sects) #define START_SECT(p) get_unaligned(&p->start_sect) @@ -101,8 +102,8 @@ static inline int is_extended_partition(struct partition *p) { - return (p->sys_ind == DOS_EXTENDED_PARTITION || - p->sys_ind == LINUX_EXTENDED_PARTITION); + return (SYS_IND(p) == DOS_EXTENDED_PARTITION || + SYS_IND(p) == LINUX_EXTENDED_PARTITION); } #ifdef CONFIG_MSDOS_PARTITION @@ -278,7 +279,7 @@ */ extern int ide_xlate_1024(kdev_t, int, const char *); unsigned int sig = *(unsigned short *)(data + 2); - if (p->sys_ind == EZD_PARTITION) { + if (SYS_IND(p) == EZD_PARTITION) { /* * The remainder of the disk must be accessed using * a translated geometry that reduces the number of @@ -291,7 +292,7 @@ data += 512; goto check_table; } - } else if (p->sys_ind == DM6_PARTITION) { + } else if (SYS_IND(p) == DM6_PARTITION) { /* * Everything on the disk is offset by 63 sectors, @@ -314,7 +315,7 @@ * DM6 signature in MBR, courtesy of OnTrack */ (void) ide_xlate_1024 (dev, 0, " [DM6:MBR]"); - } else if (p->sys_ind == DM6_AUX1PARTITION || p->sys_ind == DM6_AUX3PARTITION) { + } else if (SYS_IND(p) == DM6_AUX1PARTITION || SYS_IND(p) == DM6_AUX3PARTITION) { /* * DM6 on other than the first (boot) drive */ @@ -327,7 +328,9 @@ */ for (i = 0; i < 4 ; i++) { struct partition *q = &p[i]; - if (NR_SECTS(q) && q->sector == 1 && q->end_sector == 63) { + if (NR_SECTS(q) + && (q->sector & 63) == 1 + && (q->end_sector & 63) == 63) { unsigned int heads = q->end_head + 1; if (heads == 32 || heads == 64 || heads == 128) { @@ -363,7 +366,7 @@ hd->part[minor].nr_sects = 2; } #ifdef CONFIG_BSD_DISKLABEL - if (p->sys_ind == BSD_PARTITION) { + if (SYS_IND(p) == BSD_PARTITION) { printk(" <"); bsd_disklabel_partition(hd, MKDEV(hd->major, minor)); printk(" >"); @@ -552,6 +555,88 @@ #endif /* CONFIG_SUN_PARTITION */ +#ifdef CONFIG_AMIGA_PARTITION +#include +#include + +static __inline__ __u32 +checksum_block(__u32 *m, int size) +{ + __u32 sum = 0; + + while (size--) + sum += htonl(*m++); + return sum; +} + +static int +amiga_partition(struct gendisk *hd, unsigned int dev, unsigned long first_sector) +{ + struct buffer_head *bh; + struct RigidDiskBlock *rdb; + struct PartitionBlock *pb; + int start_sect; + int nr_sects; + int blk; + int part, res; + + set_blocksize(dev,512); + res = 0; + + for (blk = 0; blk < RDB_ALLOCATION_LIMIT; blk++) { + if(!(bh = bread(dev,blk,512))) { + printk("Dev %d: unable to read RDB block %d\n",dev,blk); + goto rdb_done; + } + if (*(__u32 *)bh->b_data == htonl(IDNAME_RIGIDDISK)) { + rdb = (struct RigidDiskBlock *)bh->b_data; + if (checksum_block((__u32 *)bh->b_data,htonl(rdb->rdb_SummedLongs) & 0x7F)) { + printk("Dev %d: RDB in block %d has bad checksum\n",dev,blk); + brelse(bh); + continue; + } + printk(" RDSK"); + blk = htonl(rdb->rdb_PartitionList); + brelse(bh); + for (part = 1; blk > 0 && part <= 16; part++) { + if (!(bh = bread(dev,blk,512))) { + printk("Dev %d: unable to read partition block %d\n", + dev,blk); + goto rdb_done; + } + pb = (struct PartitionBlock *)bh->b_data; + blk = htonl(pb->pb_Next); + if (pb->pb_ID == htonl(IDNAME_PARTITION) && checksum_block( + (__u32 *)pb,htonl(pb->pb_SummedLongs) & 0x7F) == 0 ) { + + /* Tell Kernel about it */ + + if (!(nr_sects = (htonl(pb->pb_Environment[10]) + 1 - + htonl(pb->pb_Environment[9])) * + htonl(pb->pb_Environment[3]) * + htonl(pb->pb_Environment[5]))) { + continue; + } + start_sect = htonl(pb->pb_Environment[9]) * + htonl(pb->pb_Environment[3]) * + htonl(pb->pb_Environment[5]); + add_partition(hd,current_minor,start_sect,nr_sects); + current_minor++; + res = 1; + } + brelse(bh); + } + printk("\n"); + break; + } + } + +rdb_done: + set_blocksize(dev,BLOCK_SIZE); + return res; +} +#endif /* CONFIG_AMIGA_PARTITION */ + static void check_partition(struct gendisk *hd, kdev_t dev) { static int first_time = 1; @@ -583,6 +668,10 @@ #endif #ifdef CONFIG_SUN_PARTITION if(sun_partition(hd, dev, first_sector)) + return; +#endif +#ifdef CONFIG_AMIGA_PARTITION + if(amiga_partition(hd, dev, first_sector)) return; #endif printk(" unknown partition table\n"); diff -ur --new-file old/linux/drivers/block/ht6560b.c new/linux/drivers/block/ht6560b.c --- old/linux/drivers/block/ht6560b.c Fri Apr 12 08:49:32 1996 +++ new/linux/drivers/block/ht6560b.c Mon Aug 5 07:12:25 1996 @@ -201,10 +201,8 @@ if (drive->media != ide_disk) pio = 0; /* some cdroms don't like fast modes (?) */ else - pio = ide_get_best_pio_mode (drive); + pio = ide_get_best_pio_mode(drive, pio, 5, NULL); } - if (pio > 5) - pio = 5; unit = drive->select.b.unit; hwif = HWIF(drive)->index; ht6560b_timings[hwif][unit] = pio_to_timings[pio]; diff -ur --new-file old/linux/drivers/block/ide-cd.c new/linux/drivers/block/ide-cd.c --- old/linux/drivers/block/ide-cd.c Mon Jun 3 10:10:11 1996 +++ new/linux/drivers/block/ide-cd.c Thu Aug 1 14:36:31 1996 @@ -100,14 +100,16 @@ * 3.13 May 19, 1996 -- Fixes for changer code. * 3.14 May 29, 1996 -- Add work-around for Vertos 600. * (From Hennus Bergman .) + * 3.15 July 2, 1996 -- Added support for Sanyo 3 CD changers + * from Ben Galliart with + * special help from Jeff Lightfoot + * + * 3.15a July 9, 1996 -- Improved Sanyo 3 CD changer identification + * 3.16 Jul 28, 1996 -- Fix from Gadi to reduce kernel stack usage for ioctl. * * NOTE: Direct audio reads will only work on some types of drive. * So far, i've received reports of success for Sony and Toshiba drives. * - * NOTE: The changer functions were tested with the NEC CDR-251 drive. - * They may not work with the Sanyo 3-cd changer, which i understand - * uses a different protocol. - * * ATAPI cd-rom driver. To be used with ide.c. * See Documentation/cdrom/ide-cd for usage information. * @@ -237,7 +239,8 @@ __u8 toc_valid : 1; /* Saved TOC information is current. */ __u8 door_locked : 1; /* We think that the drive door is locked. */ __u8 eject_on_close: 1; /* Drive should eject when device is closed. */ - __u8 reserved : 4; + __u8 sanyo_slot : 2; /* Sanyo 3 CD changer support */ + __u8 reserved : 2; }; #define CDROM_STATE_FLAGS(drive) ((struct ide_cd_state_flags *)&((drive)->bios_head)) @@ -1503,6 +1506,11 @@ pc.sense_data = reqbuf; pc.c[0] = TEST_UNIT_READY; + /* the Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to + switch CDs instead of supporting the LOAD_UNLOAD opcode */ + + pc.c[7] = CDROM_STATE_FLAGS (drive)->sanyo_slot % 3; + return cdrom_queue_packet_command (drive, &pc); } @@ -1965,15 +1973,38 @@ cdrom_load_unload (ide_drive_t *drive, int slot, struct atapi_request_sense *reqbuf) { - struct packet_command pc; + /* if the drive is a Sanyo 3 CD changer then TEST_UNIT_READY + (used in the cdrom_check_status function) is used to + switch CDs instead of LOAD_UNLOAD */ + + if (CDROM_STATE_FLAGS (drive)->sanyo_slot > 0) { + + if ((slot == 1) || (slot == 2)) { + CDROM_STATE_FLAGS (drive)->sanyo_slot = slot; + } else if (slot >= 0) { + CDROM_STATE_FLAGS (drive)->sanyo_slot = 3; + } else { + return 0; + } - memset (&pc, 0, sizeof (pc)); - pc.sense_data = reqbuf; + return cdrom_check_status (drive, NULL); - pc.c[0] = LOAD_UNLOAD; - pc.c[4] = 2 + (slot >= 0); - pc.c[8] = slot; - return cdrom_queue_packet_command (drive, &pc); + } else { + + /* ATAPI Rev. 2.2+ standard for requesting switching of + CDs in a multiplatter device */ + + struct packet_command pc; + + memset (&pc, 0, sizeof (pc)); + pc.sense_data = reqbuf; + + pc.c[0] = LOAD_UNLOAD; + pc.c[4] = 2 + (slot >= 0); + pc.c[8] = slot; + return cdrom_queue_packet_command (drive, &pc); + + } } @@ -2278,7 +2309,7 @@ int stat, lba; struct atapi_toc *toc; struct cdrom_read_audio ra; - char buf[CD_FRAMESIZE_RAW]; + char *buf; /* Make sure the TOC is up to date. */ stat = cdrom_read_toc (drive, NULL); @@ -2312,17 +2343,23 @@ if (lba < 0 || lba >= toc->capacity) return -EINVAL; + buf = (char *) kmalloc (CD_FRAMESIZE_RAW, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + while (ra.nframes > 0) { stat = cdrom_read_block (drive, 1, lba, buf, CD_FRAMESIZE_RAW, NULL); - if (stat) return stat; + if (stat) break; + memcpy_tofs (ra.buf, buf, CD_FRAMESIZE_RAW); ra.buf += CD_FRAMESIZE_RAW; --ra.nframes; ++lba; } - return 0; + kfree (buf); + return stat; } case CDROMREADMODE1: @@ -2330,7 +2367,7 @@ struct cdrom_msf msf; int blocksize, format, stat, lba; struct atapi_toc *toc; - char buf[CD_FRAMESIZE_RAW0]; + char *buf; if (cmd == CDROMREADMODE1) { blocksize = CD_FRAMESIZE; @@ -2358,12 +2395,17 @@ if (lba < 0 || lba >= toc->capacity) return -EINVAL; + buf = (char *) kmalloc (CD_FRAMESIZE_RAW0, GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + stat = cdrom_read_block (drive, format, lba, buf, blocksize, NULL); - if (stat) return stat; + if (stat == 0) + memcpy_tofs ((char *)arg, buf, blocksize); - memcpy_tofs ((char *)arg, buf, blocksize); - return 0; + kfree (buf); + return stat; } case CDROM_GET_UPC: { @@ -2574,6 +2616,10 @@ CDROM_CONFIG_FLAGS (drive)->no_doorlock = 0; #endif + /* by default Sanyo 3 CD changer support is turned off and + ATAPI Rev 2.2+ standard support for CD changers is used */ + CDROM_STATE_FLAGS (drive)->sanyo_slot = 0; + if (drive->id != NULL) CDROM_CONFIG_FLAGS (drive)->drq_interrupt = ((drive->id->config & 0x0060) == 0x20); @@ -2621,6 +2667,15 @@ CDROM_CONFIG_FLAGS (drive)->playmsf_as_bcd = 1; CDROM_CONFIG_FLAGS (drive)->subchan_as_bcd = 1; } + + /* Sanyo 3 CD changer uses a non-standard command + for CD changing */ + else if ((strcmp(drive->id->model, "CD-ROM CDR-C3 G") == 0) || + (strcmp(drive->id->model, "CD-ROM CDR-C3G") == 0)) { + /* uses CD in slot 0 when value is set to 3 */ + CDROM_STATE_FLAGS (drive)->sanyo_slot = 3; + } + } #endif /* not STANDARD_ATAPI */ diff -ur --new-file old/linux/drivers/block/ide-tape.c new/linux/drivers/block/ide-tape.c --- old/linux/drivers/block/ide-tape.c Fri May 3 10:07:24 1996 +++ new/linux/drivers/block/ide-tape.c Sat Aug 17 19:51:18 1996 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide-tape.c Version 1.5 - ALPHA Apr 12, 1996 + * linux/drivers/block/ide-tape.c Version 1.6 - ALPHA Aug 16, 1996 * * Copyright (C) 1995, 1996 Gadi Oxman * @@ -184,6 +184,8 @@ * Ver 1.5 Apr 12 96 Fixed shared interface operation, broken in 1.3.85. * Fixed pipelined read mode inefficiency. * Fixed nasty null dereferencing bug. + * Ver 1.6 Aug 16 96 Fixed FPU usage in the driver. + * Fixed end of media bug. * * We are currently in an *alpha* stage. The driver is not complete and not * much tested. I would strongly suggest to: @@ -1224,8 +1226,7 @@ { idetape_tape_t *tape=&(drive->tape); unsigned int allocation_length; - double service_time,nr_units; - + #if IDETAPE_DEBUG_LOG printk ("ide-tape: Reached idetape_setup\n"); #endif /* IDETAPE_DEBUG_LOG */ @@ -1259,8 +1260,11 @@ idetape_get_mode_sense_results (drive); - tape->data_buffer_size=tape->capabilities.ctl*tape->tape_block_size; - + tape->data_buffer_size = tape->capabilities.ctl * tape->tape_block_size; + while (tape->data_buffer_size > 0xffff) { + tape->capabilities.ctl /= 2; + tape->data_buffer_size = tape->capabilities.ctl * tape->tape_block_size; + } allocation_length=tape->data_buffer_size; if (tape->data_buffer_size % IDETAPE_ALLOCATION_BLOCK) allocation_length+=IDETAPE_ALLOCATION_BLOCK; @@ -1304,14 +1308,11 @@ * constantly streaming. */ - service_time=((double) tape->data_buffer_size/1024.0)/((double) tape->capabilities.speed*(1000.0/1024.0)); - nr_units=(double) tape->capabilities.buffer_size*512.0/(double) tape->data_buffer_size; - if (tape->max_number_of_stages) - tape->best_dsc_rw_frequency=(unsigned long) (0.5*nr_units*service_time*HZ); - else - tape->best_dsc_rw_frequency=(unsigned long) (service_time*HZ); - + tape->best_dsc_rw_frequency = (unsigned long) ((tape->capabilities.buffer_size * 32 * HZ) / (tape->capabilities.speed * 125)); + else + tape->best_dsc_rw_frequency = (unsigned long) ((tape->data_buffer_size * HZ) / (tape->capabilities.speed * 1000)); + /* * Ensure that the number we got makes sense. */ @@ -2105,6 +2106,7 @@ void idetape_retry_pc (ide_drive_t *drive) { + idetape_tape_t *tape = &drive->tape; idetape_packet_command_t *pc; struct request *new_rq; @@ -2116,6 +2118,7 @@ pc->buffer=pc->temp_buffer; pc->buffer_size=IDETAPE_TEMP_BUFFER_SIZE; pc->current_position=pc->temp_buffer; + tape->reset_issued = 1; idetape_queue_pc_head (drive,pc,new_rq); } @@ -3217,7 +3220,7 @@ rq.sector = tape->block_address; rq.nr_sectors = rq.current_nr_sectors = blocks; - if (tape->active_data_request != NULL || tape->current_number_of_stages <= 0.25*tape->max_number_of_stages) { + if (tape->active_data_request != NULL || tape->current_number_of_stages <= tape->max_number_of_stages / 4) { new_stage=idetape_kmalloc_stage (drive); while (new_stage != NULL) { new_stage->rq=rq; @@ -3335,7 +3338,7 @@ * keep up with the higher speeds of the tape. */ - if (tape->active_data_request == NULL && tape->current_number_of_stages >= 0.75*tape->max_number_of_stages) + if (tape->active_data_request == NULL && tape->current_number_of_stages >= (3 * tape->max_number_of_stages) / 4) idetape_insert_pipeline_into_queue (drive); if (tape->error_in_pipeline_stage) { /* Return a deferred error */ @@ -4458,8 +4461,7 @@ printk ("Reached idetape_increase_max_pipeline_stages\n"); #endif /* IDETAPE_DEBUG_LOG */ - tape->max_number_of_stages+=IDETAPE_INCREASE_STAGES_RATE* - (IDETAPE_MAX_PIPELINE_STAGES-IDETAPE_MIN_PIPELINE_STAGES); + tape->max_number_of_stages+=IDETAPE_INCREASE_STAGES_RATE; if (tape->max_number_of_stages >= IDETAPE_MAX_PIPELINE_STAGES) tape->max_number_of_stages = IDETAPE_MAX_PIPELINE_STAGES; diff -ur --new-file old/linux/drivers/block/ide-tape.h new/linux/drivers/block/ide-tape.h --- old/linux/drivers/block/ide-tape.h Fri May 3 10:07:24 1996 +++ new/linux/drivers/block/ide-tape.h Sat Aug 17 19:51:18 1996 @@ -53,7 +53,7 @@ #define IDETAPE_MIN_PIPELINE_STAGES 100 #define IDETAPE_MAX_PIPELINE_STAGES 200 -#define IDETAPE_INCREASE_STAGES_RATE 0.2 +#define IDETAPE_INCREASE_STAGES_RATE 20 /* * Assuming the tape shares an interface with another device, the default diff -ur --new-file old/linux/drivers/block/ide.c new/linux/drivers/block/ide.c --- old/linux/drivers/block/ide.c Thu Jun 6 12:42:15 1996 +++ new/linux/drivers/block/ide.c Mon Aug 12 09:24:26 1996 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide.c Version 5.43 May 14, 1996 + * linux/drivers/block/ide.c Version 5.51 Aug 10, 1996 * * Copyright (C) 1994-1996 Linus Torvalds & authors (see below) */ @@ -238,6 +238,27 @@ * Version 5.42 simplify irq-masking after probe * fix NULL pointer deref in save_match() * Version 5.43 Ugh.. unexpected_intr is back: try to exterminate it + * Version 5.44 Fix for "irq probe failed" on cmd640 + * change path on message regarding MAKEDEV.ide + * add a throttle to the unexpected_intr() messages + * Version 5.45 fix ugly parameter parsing bugs (thanks Derek) + * include Gadi's magic fix for cmd640 unexpected_intr + * include mc68000 patches from Geert Uytterhoeven + * add Gadi's fix for PCMCIA cdroms + * Version 5.46 remove the mc68000 #ifdefs for 2.0.x + * Version 5.47 fix set_tune race condition + * fix bug in earlier PCMCIA cdrom update + * Version 5.48 if def'd, invoke CMD640_DUMP_REGS when irq probe fails + * lengthen the do_reset1() pulse, for laptops + * add idebus=xx parameter for cmd640 and ali chipsets + * no_unmask flag now per-drive instead of per-hwif + * fix tune_req so that it gets done immediately + * fix missing restore_flags() in ide_ioctl + * prevent use of io_32bit on cmd640 with no prefetch + * Version 5.49 fix minor quirks in probing routines + * Version 5.50 allow values as small as 20 for idebus= + * Version 5.51 force non io_32bit in drive_cmd_intr() + * change delay_10ms() to delay_50ms() to fix problems * * Some additional driver compile-time options are in ide.h * @@ -284,9 +305,15 @@ #endif /* CONFIG_BLK_DEV_PROMISE */ static const byte ide_hwif_to_major[MAX_HWIFS] = {IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR}; - static const unsigned short default_io_base[MAX_HWIFS] = {0x1f0, 0x170, 0x1e8, 0x168}; static const byte default_irqs[MAX_HWIFS] = {14, 15, 11, 10}; +static int idebus_parameter; /* holds the "idebus=" parameter */ +static int system_bus_speed; /* holds what we think is VESA/PCI bus speed */ + +/* + * This is declared extern in ide.h, for access by other IDE modules: + */ +ide_hwif_t ide_hwifs[MAX_HWIFS]; /* master data repository */ #if (DISK_RECOVERY_TIME > 0) /* @@ -395,6 +422,32 @@ for (index = 0; index < MAX_HWIFS; ++index) init_hwif_data(index); + + idebus_parameter = 0; + system_bus_speed = 0; +} + +/* + * ide_system_bus_speed() returns what we think is the system VESA/PCI + * bus speed (in Mhz). This is used for calculating interface PIO timings. + * The default is 40 for known PCI systems, 50 otherwise. + * The "idebus=xx" parameter can be used to override this value. + * The actual value to be used is computed/displayed the first time through. + */ +int ide_system_bus_speed (void) +{ + if (!system_bus_speed) { + if (idebus_parameter) + system_bus_speed = idebus_parameter; /* user supplied value */ +#ifdef CONFIG_PCI + else if (pcibios_present()) + system_bus_speed = 40; /* safe default value for PCI */ +#endif /* CONFIG_PCI */ + else + system_bus_speed = 50; /* safe default value for VESA and PCI */ + printk("ide: Assuming %dMhz system bus speed for PIO modes; override with idebus=xx\n", system_bus_speed); + } + return system_bus_speed; } #if SUPPORT_VLB_SYNC @@ -580,6 +633,8 @@ gd->part = kmalloc (minors * sizeof(struct hd_struct), GFP_KERNEL); bs = kmalloc (minors*sizeof(int), GFP_KERNEL); + memset(gd->part, 0, minors * sizeof(struct hd_struct)); + /* cdroms and msdos f/s are examples of non-1024 blocksizes */ blksize_size[hwif->major] = bs; for (unit = 0; unit < minors; ++unit) @@ -761,9 +816,9 @@ * recover from reset very quickly, saving us the first 50ms wait time. */ OUT_BYTE(drive->ctl|6,IDE_CONTROL_REG); /* set SRST and nIEN */ - udelay(5); /* more than enough time */ + udelay(10); /* more than enough time */ OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* clear SRST, leave nIEN */ - udelay(5); /* more than enough time */ + udelay(10); /* more than enough time */ hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; ide_set_handler (drive, &reset_pollfunc, HZ/20); #endif /* OK_TO_RESET_CONTROLLER */ @@ -1158,7 +1213,10 @@ sti(); if ((stat & DRQ_STAT) && args && args[3]) { + byte io_32bit = drive->io_32bit; + drive->io_32bit = 0; ide_input_data(drive, &args[4], args[3] * SECTOR_WORDS); + drive->io_32bit = io_32bit; stat = GET_STAT(); } if (OK_STAT(stat,READY_STAT,BAD_STAT)) @@ -1174,7 +1232,7 @@ static inline void do_special (ide_drive_t *drive) { special_t *s = &drive->special; -next: + #ifdef DEBUG printk("%s: do_special: 0x%02x\n", drive->name, s->all); #endif @@ -1192,12 +1250,11 @@ s->b.recalibrate = 0; if (drive->media == ide_disk && !IS_PROMISE_DRIVE) ide_cmd(drive, WIN_RESTORE, drive->sect, &recal_intr); - } else if (s->b.set_pio) { + } else if (s->b.set_tune) { ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc; - s->b.set_pio = 0; + s->b.set_tune = 0; if (tuneproc != NULL) - tuneproc(drive, drive->pio_req); - goto next; + tuneproc(drive, drive->tune_req); } else if (s->b.set_multmode) { s->b.set_multmode = 0; if (drive->media == ide_disk) { @@ -1630,14 +1687,22 @@ if (!drive->present) continue; SELECT_DRIVE(hwif,drive); - if (!OK_STAT(stat=GET_STAT(), drive->ready_stat, BAD_STAT)) - (void) ide_dump_status(drive, "unexpected_intr", stat); + udelay(100); /* Ugly, but wait_stat() may not be safe here */ + if (!OK_STAT(stat=GET_STAT(), drive->ready_stat, BAD_STAT)) { + /* Try to not flood the console with msgs */ + static unsigned long last_msgtime = 0; + if ((last_msgtime + (HZ/2)) < jiffies) { + last_msgtime = jiffies; + (void) ide_dump_status(drive, "unexpected_intr", stat); + } + } if ((stat & DRQ_STAT)) try_to_flush_leftover_data(drive); } } } while ((hwif = hwif->next) != hwgroup->hwif); SELECT_DRIVE(hwif,hwgroup->drive); /* Ugh.. probably interrupts current I/O */ + udelay(100); /* Ugly, but wait_stat() may not be safe here */ } /* @@ -1645,8 +1710,8 @@ */ void ide_intr (int irq, void *dev_id, struct pt_regs *regs) { - ide_hwgroup_t *hwgroup = dev_id; - ide_handler_t *handler; + ide_hwgroup_t *hwgroup = dev_id; + ide_handler_t *handler; if (irq == hwgroup->hwif->irq && (handler = hwgroup->handler) != NULL) { ide_drive_t *drive = hwgroup->drive; @@ -1658,7 +1723,7 @@ cli(); /* this is necessary, as next rq may be different irq */ if (hwgroup->handler == NULL) { SET_RECOVERY_TIMER(HWIF(drive)); - ide_do_request(hwgroup); + ide_do_request(hwgroup); } } else { unexpected_intr(irq, hwgroup); @@ -1685,7 +1750,7 @@ return drive; } else if (major == IDE0_MAJOR && unit < 4) { printk("ide: probable bad entry for /dev/hd%c\n", 'a'+unit); - printk("ide: to fix it, run: /usr/src/linux/drivers/block/MAKEDEV.ide\n"); + printk("ide: to fix it, run: /usr/src/linux/scripts/MAKEDEV.ide\n"); } break; } @@ -1794,7 +1859,7 @@ unsigned long flags; if ((drive = get_info_ptr(inode->i_rdev)) == NULL) - return -ENODEV; + return -ENXIO; save_flags(flags); cli(); while (drive->busy) @@ -1899,8 +1964,9 @@ }; drive->part[0].nr_sects = current_capacity(drive); - if (drive->media == ide_disk) - resetup_one_dev(HWIF(drive)->gd, drive->select.b.unit); + if (drive->media != ide_disk) + drive->part[0].start_sect = -1; + resetup_one_dev(HWIF(drive)->gd, drive->select.b.unit); drive->busy = 0; wake_up(&drive->wqueue); @@ -2026,7 +2092,7 @@ drive->keep_settings = arg; break; case HDIO_SET_UNMASKINTR: - if (arg && HWIF(drive)->no_unmask) { + if (arg && drive->no_unmask) { restore_flags(flags); return -EPERM; } @@ -2036,8 +2102,14 @@ drive->bad_wstat = arg ? BAD_R_STAT : BAD_W_STAT; break; case HDIO_SET_32BIT: - if (arg > (1 + (SUPPORT_VLB_SYNC<<1))) + if (arg > (1 + (SUPPORT_VLB_SYNC<<1))) { + restore_flags(flags); return -EINVAL; + } + if (arg && drive->no_io_32bit) { + restore_flags(flags); + return -EPERM; + } drive->io_32bit = arg; #ifdef CONFIG_BLK_DEV_DTC2278 if (HWIF(drive)->chipset == ide_dtc2278) @@ -2103,9 +2175,14 @@ return -ENOSYS; save_flags(flags); cli(); - drive->pio_req = (int) arg; - drive->special.b.set_pio = 1; + if (drive->special.b.set_tune) { + restore_flags(flags); + return -EBUSY; + } + drive->tune_req = (byte) arg; + drive->special.b.set_tune = 1; restore_flags(flags); + (void) ide_do_drive_cmd (drive, &rq, ide_wait); return 0; RO_IOCTLS(inode->i_rdev, arg); @@ -2345,13 +2422,13 @@ } /* - * Delay for *at least* 10ms. As we don't know how much time is left + * Delay for *at least* 50ms. As we don't know how much time is left * until the next tick occurs, we wait an extra tick to be safe. * This is used only during the probing/polling for drives at boot time. */ -static void delay_10ms (void) +static void delay_50ms (void) { - unsigned long timer = jiffies + (HZ + 99)/100 + 1; + unsigned long timer = jiffies + ((HZ + 19)/20) + 1; while (timer > jiffies); } @@ -2377,7 +2454,7 @@ OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* enable device irq */ } - delay_10ms(); /* take a deep breath */ + delay_50ms(); /* take a deep breath */ if ((IN_BYTE(IDE_ALTSTATUS_REG) ^ IN_BYTE(IDE_STATUS_REG)) & ~INDEX_STAT) { printk("%s: probing with STATUS instead of ALTSTATUS\n", drive->name); hd_status = IDE_STATUS_REG; /* ancient Seagate drives */ @@ -2402,20 +2479,15 @@ (void) probe_irq_off(irqs); return 1; /* drive timed-out */ } - delay_10ms(); /* give drive a breather */ + delay_50ms(); /* give drive a breather */ } while (IN_BYTE(hd_status) & BUSY_STAT); - delay_10ms(); /* wait for IRQ and DRQ_STAT */ + delay_50ms(); /* wait for IRQ and DRQ_STAT */ if (OK_STAT(GET_STAT(),DRQ_STAT,BAD_R_STAT)) { unsigned long flags; save_flags(flags); cli(); /* some systems need this */ do_identify(drive, cmd); /* drive returned ID */ - if (drive->present && drive->media != ide_tape) { - ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc; - if (tuneproc != NULL && drive->autotune == 1) - tuneproc(drive, 255); /* auto-tune PIO mode */ - } rc = 0; /* drive responded with ID */ (void) GET_STAT(); /* clear drive IRQ */ restore_flags(flags); @@ -2428,17 +2500,19 @@ irqs = probe_irq_on(); OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* mask device irq */ udelay(5); - (void) GET_STAT(); /* clear drive IRQ */ (void) probe_irq_off(irqs); + (void) probe_irq_off(probe_irq_on()); /* clear self-inflicted irq */ + (void) GET_STAT(); /* clear drive IRQ */ + } else { /* Mmmm.. multiple IRQs.. don't know which was ours */ printk("%s: IRQ probe failed (%d)\n", drive->name, irqs); #ifdef CONFIG_BLK_DEV_CMD640 +#ifdef CMD640_DUMP_REGS if (HWIF(drive)->chipset == ide_cmd640) { - extern byte (*get_cmd640_reg)(int); printk("%s: Hmmm.. probably a driver problem.\n", drive->name); - printk("%s: cmd640 reg 09h == 0x%02x\n", drive->name, get_cmd640_reg(9)); - printk("%s: cmd640 reg 51h == 0x%02x\n", drive->name, get_cmd640_reg(0x51)); + CMD640_DUMP_REGS; } +#endif /* CMD640_DUMP_REGS */ #endif /* CONFIG_BLK_DEV_CMD640 */ } } @@ -2464,7 +2538,7 @@ static int do_probe (ide_drive_t *drive, byte cmd) { int rc; - ide_hwif_t *hwif; + ide_hwif_t *hwif = HWIF(drive); #ifdef CONFIG_BLK_DEV_IDEATAPI if (drive->present) { /* avoid waiting for inappropriate probes */ if ((drive->media != ide_disk) && (cmd == WIN_IDENTIFY)) @@ -2476,12 +2550,11 @@ drive->name, drive->present, drive->media, (cmd == WIN_IDENTIFY) ? "ATA" : "ATAPI"); #endif - hwif = HWIF(drive); SELECT_DRIVE(hwif,drive); - OUT_BYTE(drive->select.all,IDE_SELECT_REG); /* select target drive */ - delay_10ms(); /* wait for BUSY_STAT */ + delay_50ms(); if (IN_BYTE(IDE_SELECT_REG) != drive->select.all && !drive->present) { OUT_BYTE(0xa0,IDE_SELECT_REG); /* exit with drive0 selected */ + delay_50ms(); /* allow BUSY_STAT to assert & clear */ return 3; /* no i/f present: avoid killing ethernet cards */ } @@ -2498,7 +2571,7 @@ } if (drive->select.b.unit != 0) { OUT_BYTE(0xa0,IDE_SELECT_REG); /* exit with drive0 selected */ - delay_10ms(); + delay_50ms(); (void) GET_STAT(); /* ensure drive irq is clear */ } return rc; @@ -2643,6 +2716,14 @@ } } restore_flags(flags); + for (unit = 0; unit < MAX_DRIVES; ++unit) { + ide_drive_t *drive = &hwif->drives[unit]; + if (drive->present && drive->media != ide_tape) { + ide_tuneproc_t *tuneproc = HWIF(drive)->tuneproc; + if (tuneproc != NULL && drive->autotune == 1) + tuneproc(drive, 255); /* auto-tune PIO mode */ + } + } } } @@ -2679,9 +2760,11 @@ * Try matching against the supplied keywords, * and return -(index+1) if we match one */ - for (i = 0; *keywords != NULL; ++i) { - if (!strcmp(s, *keywords++)) - return -(i+1); + if (keywords != NULL) { + for (i = 0; *keywords != NULL; ++i) { + if (!strcmp(s, *keywords++)) + return -(i+1); + } } /* * Look for a series of no more than "max_vals" @@ -2728,6 +2811,15 @@ * and quite likely to cause trouble with * older/odd IDE drives. * + * "idebus=xx" : inform IDE driver of VESA/PCI bus speed in Mhz, + * where "xx" is between 20 and 66 inclusive, + * used when tuning chipset PIO modes. + * For PCI bus, 25 is correct for a P75 system, + * 30 is correct for P90,P120,P180 systems, + * and 33 is used for P100,P133,P166 systems. + * If in doubt, use idebus=33 for PCI. + * As for VLB, it is safest to not specify it. + * * "idex=noprobe" : do not attempt to access/use this interface * "idex=base" : probe for an interface at the addr specified, * where "base" is usually 0x1f0 or 0x170 @@ -2816,10 +2908,25 @@ goto bad_option; } } + + if (s[0] != 'i' || s[1] != 'd' || s[2] != 'e') + goto bad_option; + /* + * Look for bus speed option: "idebus=" + */ + if (s[3] == 'b' && s[4] == 'u' && s[5] == 's') { + if (match_parm(&s[6], NULL, vals, 1) != 1) + goto bad_option; + if (vals[0] >= 20 && vals[0] <= 66) + idebus_parameter = vals[0]; + else + printk(" -- BAD BUS SPEED! Expected value from 20 to 66"); + goto done; + } /* * Look for interface options: "idex=" */ - if (s[0] == 'i' && s[1] == 'd' && s[2] == 'e' && s[3] >= '0' && s[3] <= max_hwif) { + if (s[3] >= '0' && s[3] <= max_hwif) { /* * Be VERY CAREFUL changing this: note hardcoded indexes below */ @@ -2832,17 +2939,19 @@ /* * Cryptic check to ensure chipset not already set for hwif: */ - if (i != -1 && i != -2) { + if (i > 0 || i <= -5) { if (hwif->chipset != ide_unknown) goto bad_option; - if (i < 0 && ide_hwifs[1].chipset != ide_unknown) - goto bad_option; + if (i <= -5) { + if (ide_hwifs[1].chipset != ide_unknown) + goto bad_option; + /* + * Interface keywords work only for ide0: + */ + if (hw != 0) + goto bad_hwif; + } } - /* - * Interface keywords work only for ide0: - */ - if (i <= -6 && hw != 0) - goto bad_hwif; switch (i) { #ifdef CONFIG_BLK_DEV_PROMISE @@ -3058,7 +3167,9 @@ static int init_irq (ide_hwif_t *hwif) { unsigned long flags; +#if MAX_HWIFS > 1 unsigned int index; +#endif /* MAX_HWIFS > 1 */ ide_hwgroup_t *hwgroup; ide_hwif_t *match = NULL; @@ -3305,6 +3416,7 @@ { int index, i, rc = -1; ide_hwif_t *hwif; + ide_drive_t *drive; unsigned long flags; save_flags(flags); @@ -3322,8 +3434,14 @@ probe_hwif(hwif); if (!hwif_init(index)) break; - for (i = 0; i < hwif->gd->nr_real; i++) + for (i = 0; i < hwif->gd->nr_real; i++) { + drive = &hwif->drives[i]; revalidate_disk(MKDEV(hwif->major, i<present && drive->media == ide_cdrom) + ide_cdrom_setup(drive); +#endif /* CONFIG_BLK_DEV_IDECD */ + } rc = index; break; } diff -ur --new-file old/linux/drivers/block/ide.h new/linux/drivers/block/ide.h --- old/linux/drivers/block/ide.h Sun Jun 9 11:24:29 1996 +++ new/linux/drivers/block/ide.h Tue Aug 20 17:10:27 1996 @@ -41,6 +41,13 @@ #define FANCY_STATUS_DUMPS 1 /* 0 to reduce kernel size */ #endif +#ifdef CONFIG_BLK_DEV_CMD640 +#if 0 /* change to 1 when debugging cmd640 problems */ +void cmd640_dump_regs (void); +#define CMD640_DUMP_REGS cmd640_dump_regs() /* for debugging cmd640 chipset */ +#endif +#endif /* CONFIG_BLK_DEV_CMD640 */ + #if defined(CONFIG_BLK_DEV_IDECD) || defined(CONFIG_BLK_DEV_IDETAPE) #define CONFIG_BLK_DEV_IDEATAPI 1 #endif @@ -135,7 +142,11 @@ * Timeouts for various operations: */ #define WAIT_DRQ (5*HZ/100) /* 50msec - spec allows up to 20ms */ +#ifdef CONFIG_APM +#define WAIT_READY (5*HZ) /* 5sec - some laptops are very slow */ +#else #define WAIT_READY (3*HZ/100) /* 30msec - should be instantaneous */ +#endif /* CONFIG_APM */ #define WAIT_PIDENTIFY (1*HZ) /* 1sec - should be less than 3ms (?) */ #define WAIT_WORSTCASE (30*HZ) /* 30sec - worst case when spinning up */ #define WAIT_CMD (10*HZ) /* 10sec - maximum wait for an IRQ to happen */ @@ -287,7 +298,7 @@ unsigned set_geometry : 1; /* respecify drive geometry */ unsigned recalibrate : 1; /* seek to cyl 0 */ unsigned set_multmode : 1; /* set multmode count */ - unsigned set_pio : 1; /* set pio mode */ + unsigned set_tune : 1; /* tune interface for drive */ unsigned reserved : 4; /* unused */ } b; } special_t; @@ -313,6 +324,8 @@ unsigned using_dma : 1; /* disk is using dma for read/write */ unsigned forced_geom : 1; /* 1 if hdx=c,h,s was given at boot */ unsigned unmask : 1; /* flag: okay to unmask other irqs */ + unsigned no_unmask : 1; /* disallow setting unmask bit */ + unsigned no_io_32bit : 1; /* disallow enabling 32bit I/O */ unsigned nobios : 1; /* flag: do not probe bios for drive */ unsigned autotune : 2; /* 1=autotune, 2=noautotune, 0=default */ #if FAKE_FDISK_FOR_EZDRIVE @@ -324,7 +337,7 @@ byte ready_stat; /* min status value for drive ready */ byte mult_count; /* current multiple sector setting */ byte mult_req; /* requested multiple sector setting */ - byte pio_req; /* requested multiple sector setting */ + byte tune_req; /* requested drive tuning setting */ byte io_32bit; /* 0=16-bit, 1=32-bit, 2/3=32bit+sync */ byte bad_wstat; /* used for ignoring WRERR_STAT */ byte sect0; /* offset of first sector for DM6:DDO */ @@ -418,7 +431,6 @@ unsigned noprobe : 1; /* don't probe for this interface */ unsigned present : 1; /* this interface exists */ unsigned serialized : 1; /* serialized operation with mate hwif */ - unsigned no_unmask : 1; /* disallow setting unmask bits */ unsigned sharing_irq: 1; /* 1 = sharing irq with another hwif */ #ifdef CONFIG_BLK_DEV_PROMISE unsigned is_promise2: 1; /* 2nd i/f on promise DC4030 */ @@ -457,11 +469,10 @@ * should be using pointers to a drive (ide_drive_t *) or * pointers to a hwif (ide_hwif_t *), rather than indexing this * structure directly (the allocation/layout may change!). + * */ -#ifdef _IDE_C - ide_hwif_t ide_hwifs[MAX_HWIFS]; /* master data repository */ -#else -extern ide_hwif_t ide_hwifs[]; +#ifndef _IDE_C +extern ide_hwif_t ide_hwifs[]; /* master data repository */ #endif /* @@ -593,6 +604,14 @@ * stat/err are used only when (HWGROUP(drive)->rq->cmd == IDE_DRIVE_CMD). */ void ide_end_drive_cmd (ide_drive_t *drive, byte stat, byte err); + +/* + * ide_system_bus_speed() returns what we think is the system VESA/PCI + * bus speed (in Mhz). This is used for calculating interface PIO timings. + * The default is 40 for known PCI systems, 50 otherwise. + * The "idebus=xx" parameter can be used to override this value. + */ +int ide_system_bus_speed (void); /* * ide_multwrite() transfers a block of up to mcount sectors of data diff -ur --new-file old/linux/drivers/block/ide_modes.h new/linux/drivers/block/ide_modes.h --- old/linux/drivers/block/ide_modes.h Sun May 12 20:21:04 1996 +++ new/linux/drivers/block/ide_modes.h Mon Aug 5 07:12:25 1996 @@ -15,13 +15,43 @@ #if defined(CONFIG_BLK_DEV_CMD640) || defined(CONFIG_IDE_CHIPSETS) +/* + * Standard (generic) timings for PIO modes, from ATA2 specification. + * These timings are for access to the IDE data port register *only*. + * Some drives may specify a mode, while also specifying a different + * value for cycle_time (from drive identification data). + */ +typedef struct ide_pio_timings_s { + int setup_time; /* Address setup (ns) minimum */ + int active_time; /* Active pulse (ns) minimum */ + int cycle_time; /* Cycle time (ns) minimum = (setup + active + recovery) */ +} ide_pio_timings_t; + +typedef struct ide_pio_data_s { + byte pio_mode; + byte use_iordy; + byte overridden; + byte blacklisted; + unsigned int cycle_time; +} ide_pio_data_t; + #ifndef _IDE_C int ide_scan_pio_blacklist (char *model); -unsigned int ide_get_best_pio_mode (ide_drive_t *drive); +byte ide_get_best_pio_mode (ide_drive_t *drive, byte mode_wanted, byte max_mode, ide_pio_data_t *d); +extern const ide_pio_timings_t ide_pio_timings[6]; #else /* _IDE_C */ +const ide_pio_timings_t ide_pio_timings[6] = { + { 70, 165, 600 }, /* PIO Mode 0 */ + { 50, 125, 383 }, /* PIO Mode 1 */ + { 30, 100, 240 }, /* PIO Mode 2 */ + { 30, 80, 180 }, /* PIO Mode 3 with IORDY */ + { 25, 70, 120 }, /* PIO Mode 4 with IORDY */ + { 20, 50, 100 } /* PIO Mode 5 with IORDY (nonstandard) */ +}; + /* * Black list. Some drives incorrectly report their maximal PIO mode, * at least in respect to CMD640. Here we keep info on some known drives. @@ -31,6 +61,7 @@ int pio; } ide_pio_blacklist [] = { /* { "Conner Peripherals 1275MB - CFS1275A", 4 }, */ + { "Conner Peripherals 540MB - CFS540A", 3 }, { "WDC AC2700", 3 }, { "WDC AC2540", 3 }, @@ -38,6 +69,7 @@ { "WDC AC2340", 3 }, { "WDC AC2250", 0 }, { "WDC AC2200", 0 }, + { "WDC AC21200", 4 }, { "WDC AC2120", 0 }, { "WDC AC2850", 3 }, { "WDC AC1270", 3 }, @@ -46,7 +78,6 @@ { "WDC AC280", 0 }, /* { "WDC AC21000", 4 }, */ { "WDC AC31000", 3 }, -/* { "WDC AC21200", 4 }, */ { "WDC AC31200", 3 }, /* { "WDC AC31600", 4 }, */ @@ -112,31 +143,80 @@ } /* - * This routine returns the recommended PIO mode for a given drive, + * This routine returns the recommended PIO settings for a given drive, * based on the drive->id information and the ide_pio_blacklist[]. * This is used by most chipset support modules when "auto-tuning". */ -unsigned int ide_get_best_pio_mode (ide_drive_t *drive) -{ - unsigned int pio = 0; - struct hd_driveid *id = drive->id; - if (id != NULL) { - if (HWIF(drive)->chipset != ide_cmd640 && !strcmp("QUANTUM FIREBALL1080A", id->model)) - pio = 4; - else - pio = ide_scan_pio_blacklist(id->model); - if (pio == -1) { - pio = (id->tPIO < 2) ? id->tPIO : 2; - if (id->field_valid & 2) { - byte modes = id->eide_pio_modes; - if (modes & 4) pio = 5; - else if (modes & 2) pio = 4; - else if (modes & 1) pio = 3; +/* + * Drive PIO mode auto selection + */ +byte ide_get_best_pio_mode (ide_drive_t *drive, byte mode_wanted, byte max_mode, ide_pio_data_t *d) +{ + int pio_mode; + int cycle_time = 0; + int use_iordy = 0; + struct hd_driveid* id = drive->id; + int overridden = 0; + int blacklisted = 0; + + if (mode_wanted != 255) { + pio_mode = mode_wanted; + } else if (!drive->id) { + pio_mode = 0; + } else if ((pio_mode = ide_scan_pio_blacklist(id->model)) != -1) { + overridden = 1; + blacklisted = 1; + use_iordy = (pio_mode > 2); + } else { + pio_mode = id->tPIO; + if (pio_mode > 2) { /* 2 is maximum allowed tPIO value */ + pio_mode = 2; + overridden = 1; + } + if (id->field_valid & 2) { /* drive implements ATA2? */ + if (id->capability & 8) { /* drive supports use_iordy? */ + use_iordy = 1; + cycle_time = id->eide_pio_iordy; + if (id->eide_pio_modes & 7) { + overridden = 0; + if (id->eide_pio_modes & 4) + pio_mode = 5; + else if (id->eide_pio_modes & 2) + pio_mode = 4; + else + pio_mode = 3; + } + } else { + cycle_time = id->eide_pio; } } + + /* + * Conservative "downgrade" for all pre-ATA2 drives + */ + if (pio_mode && pio_mode < 4) { + pio_mode--; + overridden = 1; +#if 0 + use_iordy = (pio_mode > 2); +#endif + if (cycle_time && cycle_time < ide_pio_timings[pio_mode].cycle_time) + cycle_time = 0; /* use standard timing */ + } + } + if (pio_mode > max_mode) { + pio_mode = max_mode; + cycle_time = 0; + } + if (d) { + d->pio_mode = pio_mode; + d->cycle_time = cycle_time ? cycle_time : ide_pio_timings[pio_mode].cycle_time; + d->use_iordy = use_iordy; + d->overridden = overridden; + d->blacklisted = blacklisted; } - return pio; + return pio_mode; } #endif /* _IDE_C */ diff -ur --new-file old/linux/drivers/block/ll_rw_blk.c new/linux/drivers/block/ll_rw_blk.c --- old/linux/drivers/block/ll_rw_blk.c Tue Jun 4 08:14:23 1996 +++ new/linux/drivers/block/ll_rw_blk.c Thu Aug 15 08:55:43 1996 @@ -274,7 +274,7 @@ tmp->next = req; /* for SCSI devices, call request_fn unconditionally */ - if (scsi_major(MAJOR(req->rq_dev))) + if (scsi_blk_major(MAJOR(req->rq_dev))) (dev->request_fn)(); sti(); diff -ur --new-file old/linux/drivers/block/loop.c new/linux/drivers/block/loop.c --- old/linux/drivers/block/loop.c Mon May 6 06:28:51 1996 +++ new/linux/drivers/block/loop.c Mon Jul 15 12:47:39 1996 @@ -6,6 +6,7 @@ * Copyright 1993 by Theodore Ts'o. Redistribution of this file is * permitted under the GNU Public License. * + * more DES encryption plus IDEA encryption by Nicholas J. Leon, June 20, 1996 * DES encryption plus some minor changes by Werner Almesberger, 30-MAY-1993 * * Modularized and updated for 1.1.16 kernel - Mitch Dsouza 28th May 1994 @@ -15,6 +16,7 @@ #include +#include #include #include #include @@ -22,9 +24,14 @@ #include -#ifdef DES_AVAILABLE -#include "des.h" +#ifdef CONFIG_BLK_DEV_LOOP_DES +#include +#endif + +#ifdef CONFIG_BLK_DEV_LOOP_IDEA +#include #endif + #include /* must follow des.h */ #define MAJOR_NR LOOP_MAJOR @@ -41,6 +48,7 @@ #define MAX_LOOP 8 static struct loop_device loop_dev[MAX_LOOP]; static int loop_sizes[MAX_LOOP]; +static int loop_blksizes[MAX_LOOP]; /* * Transfer functions @@ -113,6 +121,23 @@ } #endif +#ifdef IDEA_AVAILABLE + +extern void idea_encrypt_block(idea_key,char *,char *,int); + +static int transfer_idea(struct loop_device *lo, int cmd, char *raw_buf, + char *loop_buf, int size) +{ + if (cmd==READ) { + idea_encrypt_block(lo->lo_idea_en_key,raw_buf,loop_buf,size); + } + else { + idea_encrypt_block(lo->lo_idea_de_key,loop_buf,raw_buf,size); + } + return 0; +} +#endif + static transfer_proc_t xfer_funcs[MAX_LOOP] = { transfer_none, /* LO_CRYPT_NONE */ transfer_xor, /* LO_CRYPT_XOR */ @@ -121,7 +146,11 @@ #else NULL, /* LO_CRYPT_DES */ #endif - 0 /* LO_CRYPT_IDEA */ +#ifdef IDEA_AVAILABLE /* LO_CRYPT_IDEA */ + transfer_idea +#else + NULL +#endif }; @@ -142,6 +171,7 @@ else size = MAX_DISK_SIZE; } + loop_sizes[lo->lo_number] = size; } @@ -174,7 +204,7 @@ offset = 0; } else { block = CURRENT->sector / (blksize >> 9); - offset = CURRENT->sector % (blksize >> 9); + offset = (CURRENT->sector % (blksize >> 9)) << 9; } block += lo->lo_offset / blksize; offset += lo->lo_offset % blksize; @@ -183,6 +213,7 @@ offset -= blksize; } len = CURRENT->current_nr_sectors << 9; + if (CURRENT->cmd == WRITE) { if (lo->lo_flags & LO_FLAGS_READ_ONLY) goto error_out; @@ -225,8 +256,10 @@ brelse(bh); goto error_out; } - if (CURRENT->cmd == WRITE) + if (CURRENT->cmd == WRITE) { + mark_buffer_uptodate(bh, 1); mark_buffer_dirty(bh, 1); + } brelse(bh); dest_addr += size; len -= size; @@ -335,6 +368,20 @@ memcpy(lo->lo_des_init,info.lo_init,8); break; #endif +#ifdef IDEA_AVAILABLE + case LO_CRYPT_IDEA: + { + uint16 tmpkey[8]; + + if (info.lo_encrypt_key_size != IDEAKEYSIZE) + return -EINVAL; + /* create key in lo-> from info.lo_encrypt_key */ + memcpy(tmpkey,info.lo_encrypt_key,sizeof(tmpkey)); + en_key_idea(tmpkey,lo->lo_idea_en_key); + de_key_idea(lo->lo_idea_en_key,lo->lo_idea_de_key); + break; + } +#endif default: return -EINVAL; } @@ -494,6 +541,12 @@ } #ifndef MODULE printk("loop: registered device at major %d\n", MAJOR_NR); +#ifdef DES_AVAILABLE + printk("loop: DES encryption available\n"); +#endif +#ifdef IDEA_AVAILABLE + printk("loop: IDEA encryption available\n"); +#endif #endif blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; @@ -502,7 +555,9 @@ loop_dev[i].lo_number = i; } memset(&loop_sizes, 0, sizeof(loop_sizes)); + memset(&loop_blksizes, 0, sizeof(loop_blksizes)); blk_size[MAJOR_NR] = loop_sizes; + blksize_size[MAJOR_NR] = loop_blksizes; return 0; } diff -ur --new-file old/linux/drivers/block/md.c new/linux/drivers/block/md.c --- old/linux/drivers/block/md.c Mon May 20 06:50:46 1996 +++ new/linux/drivers/block/md.c Sat Jun 29 23:04:00 1996 @@ -163,6 +163,7 @@ { md_dev[minor].devices[i].size &= ~(min - 1); md_size[minor] += md_dev[minor].devices[i].size; + md_dev[minor].devices[i].offset=i ? (md_dev[minor].devices[i-1].offset + md_dev[minor].devices[i-1].size) : 0; } md_dev[minor].pers=pers[pnum]; @@ -218,6 +219,7 @@ clear_inode (md_dev[minor].devices[i].inode); md_dev[minor].nb_dev=md_size[minor]=0; + md_hd_struct[minor].nr_sects=0; md_dev[minor].pers=NULL; set_ra (); /* calculate new read_ahead */ @@ -257,14 +259,7 @@ /* Sizes are now rounded at run time */ md_dev[minor].devices[i].size=gen_real->sizes[MINOR(dev)]; - md_dev[minor].devices[i].offset=i ? - (md_dev[minor].devices[i-1].offset + md_dev[minor].devices[i-1].size) : 0; - - if (!i) - md_size[minor]=0; - - md_size[minor]+=md_dev[minor].devices[i].size; - + printk ("REGISTER_DEV %s to md%x done\n", partition_name(dev), minor); return (0); } @@ -372,11 +367,33 @@ } +static int md_read (struct inode *inode, struct file *file, + char *buf, int count) +{ + int minor=MINOR(inode->i_rdev); + + if (!md_dev[minor].pers) /* Check if device is being run */ + return -ENXIO; + + return block_read (inode, file, buf, count); +} + +static int md_write (struct inode *inode, struct file *file, + const char *buf, int count) +{ + int minor=MINOR(inode->i_rdev); + + if (!md_dev[minor].pers) /* Check if device is being run */ + return -ENXIO; + + return block_write (inode, file, buf, count); +} + static struct file_operations md_fops= { NULL, - block_read, - block_write, + md_read, + md_write, NULL, NULL, md_ioctl, @@ -431,6 +448,7 @@ { md_blocksizes[i] = 1024; md_gendisk.part[i].start_sect=-1; /* avoid partition check */ + md_gendisk.part[i].nr_sects=0; md_dev[i].pers=NULL; } @@ -448,7 +466,7 @@ int get_md_status (char *page) { - int sz=0, i, j; + int sz=0, i, j, size; sz+=sprintf( page+sz, "Personalities : "); for (i=0; iname); + size=0; for (j=0; j 3) - pio = 3; + pio = ide_get_best_pio_mode(drive, pio, 3, NULL); save_flags(flags); cli(); diff -ur --new-file old/linux/drivers/block/rd.c new/linux/drivers/block/rd.c --- old/linux/drivers/block/rd.c Sun Apr 28 17:47:40 1996 +++ new/linux/drivers/block/rd.c Tue Jul 2 18:08:41 1996 @@ -233,7 +233,7 @@ #endif if (DEVICE_NR(inode->i_rdev) >= NUM_RAMDISKS) - return -ENODEV; + return -ENXIO; MOD_INC_USE_COUNT; diff -ur --new-file old/linux/drivers/block/rz1000.c new/linux/drivers/block/rz1000.c --- old/linux/drivers/block/rz1000.c Thu Mar 28 07:19:44 1996 +++ new/linux/drivers/block/rz1000.c Mon Aug 5 07:12:25 1996 @@ -45,8 +45,10 @@ if ((rc = pcibios_read_config_word(bus, fn, 0x40, ®)) || (rc = pcibios_write_config_word(bus, fn, 0x40, reg & 0xdfff))) { - ide_hwifs[0].no_unmask = 1; - ide_hwifs[1].no_unmask = 1; + ide_hwifs[0].drives[0].no_unmask = 1; + ide_hwifs[0].drives[1].no_unmask = 1; + ide_hwifs[1].drives[0].no_unmask = 1; + ide_hwifs[1].drives[1].no_unmask = 1; ide_hwifs[0].serialized = 1; ide_hwifs[1].serialized = 1; ide_pci_access_error (rc); diff -ur --new-file old/linux/drivers/block/triton.c new/linux/drivers/block/triton.c --- old/linux/drivers/block/triton.c Tue Apr 9 13:36:32 1996 +++ new/linux/drivers/block/triton.c Tue Aug 13 07:40:15 1996 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/triton.c Version 1.10 Apr 3, 1996 + * linux/drivers/block/triton.c Version 1.13 Aug 12, 1996 * * Copyright (c) 1995-1996 Mark Lord * May be copied or modified under the terms of the GNU General Public License @@ -7,7 +7,10 @@ /* * This module provides support for the Bus Master IDE DMA function - * of the Intel PCI Triton chipset (82371FB). + * of the Intel PCI Triton I/II chipsets (i82371FB or i82371SB). + * + * Pretty much the same code will work for the OPTi "Viper" chipset. + * Look for DMA support for this in linux kernel 2.1.xx, when it appears. * * DMA is currently supported only for hard disk drives (not cdroms). * @@ -15,11 +18,11 @@ * after broader experience has been obtained with hard disks. * * Up to four drives may be enabled for DMA, and the Triton chipset will - * (hopefully) arbitrate the PCI bus among them. Note that the 82371FB chip + * (hopefully) arbitrate the PCI bus among them. Note that the i82371 chip * provides a single "line buffer" for the BM IDE function, so performance of * multiple (two) drives doing DMA simultaneously will suffer somewhat, * as they contest for that resource bottleneck. This is handled transparently - * inside the 82371FB chip. + * inside the i82371 chip. * * By default, DMA support is prepared for use, but is currently enabled only * for drives which support multi-word DMA mode2 (mword2), or which are @@ -116,6 +119,8 @@ #include "ide.h" +#undef DISPLAY_TRITON_TIMINGS /* define this to display timings */ + /* * good_dma_drives() lists the model names (from "hdparm -i") * of drives which do not support mword2 DMA but which are @@ -223,7 +228,7 @@ if (bcount > size) bcount = size; *table++ = addr; - *table++ = bcount; + *table++ = bcount & 0xffff; addr += bcount; size -= bcount; } @@ -309,7 +314,7 @@ return 1; outl(virt_to_bus (HWIF(drive)->dmatable), dma_base + 4); /* PRD table */ outb(reading, dma_base); /* specify r/w */ - outb(0x26, dma_base+2); /* clear status bits */ + outb(inb(dma_base+2)|0x06, dma_base+2); /* clear status bits */ #ifdef CONFIG_BLK_DEV_IDEATAPI if (drive->media != ide_disk) return 0; @@ -320,9 +325,10 @@ return 0; } +#ifdef DISPLAY_TRITON_TIMINGS /* * print_triton_drive_flags() displays the currently programmed options - * in the 430FX (Triton) chipset for a given drive. + * in the i82371 (Triton) for a given drive. * * If fastDMA is "no", then slow ISA timings are used for DMA data xfers. * If fastPIO is "no", then slow ISA timings are used for PIO data xfers. @@ -341,6 +347,7 @@ printk(" IORDY=%s", (flags&2) ? "on " : "off"); printk(" fastPIO=%s\n", ((flags&9)==1) ? "on " : "off"); } +#endif /* DISPLAY_TRITON_TIMINGS */ static void init_triton_dma (ide_hwif_t *hwif, unsigned short base) { @@ -354,11 +361,11 @@ hwif->dma_base = base; if (!dmatable) { /* - * Since we know we are on a PCI bus, we could - * actually use __get_free_pages() here instead + * The BM-DMA uses a full 32-bits, so we can + * safely use __get_free_page() here instead * of __get_dma_pages() -- no ISA limitations. */ - dmatable = __get_dma_pages(GFP_KERNEL, 0); + dmatable = __get_free_page(GFP_KERNEL); } if (dmatable) { hwif->dmatable = (unsigned long *) dmatable; @@ -382,7 +389,7 @@ unsigned short pcicmd; unsigned int bmiba, timings; - printk("ide: 430FX (Triton) on PCI bus %d function %d\n", bus, fn); + printk("ide: i82371 PIIX (Triton) on PCI bus %d function %d\n", bus, fn); /* * See if IDE and BM-DMA features are enabled: */ @@ -434,31 +441,54 @@ * Save the dma_base port addr for each interface */ for (h = 0; h < MAX_HWIFS; ++h) { +#ifdef DISPLAY_TRITON_TIMINGS byte s_clks, r_clks; + unsigned short devid; +#endif /* DISPLAY_TRITON_TIMINGS */ ide_hwif_t *hwif = &ide_hwifs[h]; unsigned short time; if (hwif->io_base == 0x1f0) { time = timings & 0xffff; - if ((timings & 0x8000) == 0) /* interface enabled? */ + if ((time & 0x8000) == 0) /* interface enabled? */ continue; hwif->chipset = ide_triton; if (dma_enabled) init_triton_dma(hwif, bmiba); } else if (hwif->io_base == 0x170) { time = timings >> 16; - if ((timings & 0x8000) == 0) /* interface enabled? */ + if ((time & 0x8000) == 0) /* interface enabled? */ continue; hwif->chipset = ide_triton; if (dma_enabled) init_triton_dma(hwif, bmiba + 8); } else continue; +#ifdef DISPLAY_TRITON_TIMINGS s_clks = ((~time >> 12) & 3) + 2; r_clks = ((~time >> 8) & 3) + 1; printk(" %s timing: (0x%04x) sample_CLKs=%d, recovery_CLKs=%d\n", hwif->name, time, s_clks, r_clks); + if ((time & 0x40) && !pcibios_read_config_word(bus, fn, 0x02, &devid) + && devid == PCI_DEVICE_ID_INTEL_82371SB_1) + { + byte stime; + if (pcibios_read_config_byte(bus, fn, 0x44, &stime)) { + if (hwif->io_base == 0x1f0) { + s_clks = ~stime >> 6; + r_clks = ~stime >> 4; + } else { + s_clks = ~stime >> 2; + r_clks = ~stime; + } + s_clks = (s_clks & 3) + 2; + r_clks = (r_clks & 3) + 1; + printk(" slave: sample_CLKs=%d, recovery_CLKs=%d\n", + s_clks, r_clks); + } + } print_triton_drive_flags (0, time & 0xf); print_triton_drive_flags (1, (time >> 4) & 0xf); +#endif /* DISPLAY_TRITON_TIMINGS */ } quit: if (rc) printk("ide: pcibios access failed - %s\n", pcibios_strerror(rc)); diff -ur --new-file old/linux/drivers/block/umc8672.c new/linux/drivers/block/umc8672.c --- old/linux/drivers/block/umc8672.c Fri May 10 07:03:33 1996 +++ new/linux/drivers/block/umc8672.c Mon Aug 5 07:26:00 1996 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/umc8672.c Version 0.04 May 09, 1996 + * linux/drivers/block/umc8672.c Version 0.05 Jul 31, 1996 * * Copyright (C) 1995-1996 Linus Torvalds & author (see below) */ @@ -16,6 +16,8 @@ * * Version 0.02 now configs/compiles separate from ide.c -ml * Version 0.03 enhanced auto-tune, fix display bug + * Version 0.05 replace sti() with restore_flags() -ml + * add detection of possible race condition -ml */ /* @@ -81,10 +83,7 @@ static void umc_set_speeds (byte speeds[]) { int i, tmp; - unsigned long flags; - save_flags(flags); - cli (); outb_p (0x5A,0x108); /* enable umc */ out_umc (0xd7,(speedtab[0][speeds[2]] | (speedtab[0][speeds[3]]<<4))); @@ -101,7 +100,6 @@ out_umc (0xd8+i,speedtab[2][speeds[i]]); } outb_p (0xa5,0x108); /* disable umc */ - restore_flags(flags); printk ("umc8672: drive speeds [0 to 11]: %d %d %d %d\n", speeds[0], speeds[1], speeds[2], speeds[3]); @@ -109,36 +107,44 @@ static void tune_umc (ide_drive_t *drive, byte pio) { - if (pio == 255) - pio = ide_get_best_pio_mode(drive); - if (pio > 4) - pio = 4; + unsigned long flags; + ide_hwgroup_t *hwgroup = ide_hwifs[HWIF(drive)->index^1].hwgroup; - current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio]; - umc_set_speeds (current_speeds); + pio = ide_get_best_pio_mode(drive, pio, 4, NULL); + printk("%s: setting umc8672 to PIO mode%d (speed %d)\n", drive->name, pio, pio_to_umc[pio]); + save_flags(flags); + cli(); + if (hwgroup && hwgroup->handler != NULL) { + printk("umc8672: other interface is busy: exiting tune_umc()\n"); + } else { + current_speeds[drive->name[2] - 'a'] = pio_to_umc[pio]; + umc_set_speeds (current_speeds); + } + restore_flags(flags); } void init_umc8672 (void) /* called from ide.c */ { unsigned long flags; + save_flags(flags); + cli (); if (check_region(0x108, 2)) { + restore_flags(flags); printk("\numc8672: PORTS 0x108-0x109 ALREADY IN USE\n"); return; } - save_flags(flags); - cli (); outb_p (0x5A,0x108); /* enable umc */ if (in_umc (0xd5) != 0xa0) { - sti (); + restore_flags(flags); printk ("umc8672: not found\n"); return; } outb_p (0xa5,0x108); /* disable umc */ - restore_flags(flags); umc_set_speeds (current_speeds); + restore_flags(flags); request_region(0x108, 2, "umc8672"); ide_hwifs[0].chipset = ide_umc8672; diff -ur --new-file old/linux/drivers/block/xd.c new/linux/drivers/block/xd.c --- old/linux/drivers/block/xd.c Wed Jun 5 09:25:29 1996 +++ new/linux/drivers/block/xd.c Tue Jul 2 18:08:41 1996 @@ -211,7 +211,7 @@ return (0); } else - return (-ENODEV); + return -ENXIO; } /* do_xd_request: handle an incoming request */ diff -ur --new-file old/linux/drivers/cdrom/cdrom.c new/linux/drivers/cdrom/cdrom.c --- old/linux/drivers/cdrom/cdrom.c Mon May 13 06:39:35 1996 +++ new/linux/drivers/cdrom/cdrom.c Wed Aug 14 09:21:03 1996 @@ -21,7 +21,7 @@ #define FM_WRITE 0x2 /* file mode write bit */ -#define VERSION "$Id: cdrom.c,v 0.4 1996/04/17 20:47:50 david Exp david $" +#define VERSION "$Id: cdrom.c,v 0.8 1996/08/10 10:52:11 david Exp $" /* Not-exported routines. */ int cdrom_open(struct inode *ip, struct file *fp); @@ -351,7 +351,7 @@ return cdo->options; case CDROM_SELECT_SPEED: - if (0 <= arg && arg < (int) (cdo->speed + 0.5) && + if (0 <= arg && arg <= cdo->speed && cdo->capability & ~cdo->mask & CDC_SELECT_SPEED) return cdo->select_speed(dev, arg); else @@ -457,7 +457,7 @@ } case CDROMPLAYMSF: { struct cdrom_msf msf; - GETARG(struct cdrom_mdf, msf); + GETARG(struct cdrom_msf, msf); return cdo->audio_ioctl(dev, cmd, &msf); } case CDROMPLAYTRKIND: { @@ -467,13 +467,13 @@ } case CDROMVOLCTRL: { struct cdrom_volctrl volume; - GETARG(struct cdrom_volctl, volume); + GETARG(struct cdrom_volctrl, volume); return cdo->audio_ioctl(dev, cmd, &volume); } case CDROMVOLREAD: { struct cdrom_volctrl volume; if (!cdo->audio_ioctl(dev, cmd, &volume)) { - PUTARG(struct cdrom_volctl, volume); + PUTARG(struct cdrom_volctrl, volume); return 0; } return -EINVAL; diff -ur --new-file old/linux/drivers/cdrom/cm206.c new/linux/drivers/cdrom/cm206.c --- old/linux/drivers/cdrom/cm206.c Thu May 30 14:40:07 1996 +++ new/linux/drivers/cdrom/cm206.c Wed Aug 14 09:21:03 1996 @@ -98,7 +98,7 @@ * - Philips/LMS cm260 product specification * * David van Leeuwen, david@tm.tno.nl. */ -#define VERSION "$Id: cm206.c,v 0.99 1996/04/14 20:26:26 david Exp david $" +#define VERSION "$Id: cm206.c,v 0.99.1.1 1996/08/11 10:35:01 david Exp $" #include @@ -1086,7 +1086,7 @@ CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_MULTI_SESSION | CDC_MEDIA_CHANGED | CDC_MCN | CDC_PLAY_AUDIO, /* capability */ 0, /* mask flags */ - 2.0, /* maximum speed */ + 2, /* maximum speed */ 1, /* number of minor devices */ 1, /* number of discs */ 0, /* options, ignored */ @@ -1188,12 +1188,14 @@ } else printk(" IRQ %d found\n", cm206_irq); #else + cli(); reset_cm260(); /* Now, the problem here is that reset_cm260 can generate an interrupt. It seems that this can cause a kernel oops some time later. So we wait a while and `service' this interrupt. */ udelay(10); outw(dc_normal | READ_AHEAD, r_data_control); + sti(); printk(" using IRQ %d\n", cm206_irq); #endif if (send_receive_polled(c_drive_configuration) != c_drive_configuration) diff -ur --new-file old/linux/drivers/cdrom/mcdx.c new/linux/drivers/cdrom/mcdx.c --- old/linux/drivers/cdrom/mcdx.c Thu Jun 6 21:23:08 1996 +++ new/linux/drivers/cdrom/mcdx.c Tue Jul 23 09:26:54 1996 @@ -39,7 +39,7 @@ * Daniel v. Mosnenck (he sent me the Technical and Programming Reference) * Gerd Knorr (he lent me his PhotoCD) * Nils Faerber and Roger E. Wolff (extensively tested the LU portion) - * Andreas Kies (testing the mysterious hang up's) + * Andreas Kies (testing the mysterious hang-ups) * Heiko Eissfeldt (VERIFY_READ/WRITE) * Marcin Dalecki (improved performance, shortened code) * ... somebody forgotten? diff -ur --new-file old/linux/drivers/cdrom/sbpcd.c new/linux/drivers/cdrom/sbpcd.c --- old/linux/drivers/cdrom/sbpcd.c Fri Jun 7 14:28:13 1996 +++ new/linux/drivers/cdrom/sbpcd.c Mon Aug 12 12:44:47 1996 @@ -13,7 +13,7 @@ * labelled E2550UA or MK4015 or 2800F). */ -#define VERSION "v4.4 Eberhard Moenkeberg " +#define VERSION "v4.5 Eberhard Moenkeberg " /* Copyright (C) 1993, 1994, 1995 Eberhard Moenkeberg * @@ -284,10 +284,18 @@ * Inhibited "play audio" attempts with data CDs. Provisions for a * "data-safe" handling of "mixed" (data plus audio) Cds. * + * 4.5 Meanwhile Gonzalo Tornaria (GTL) built a + * special end_request routine: we seem to have to take care for not + * to have two processes working at the request list. My understanding + * was and is that ll_rw_blk should not call do_sbpcd_request as long + * as there is still one call active (the first call will care for all + * outstanding I/Os, and if a second call happens, that is a bug in + * ll_rw_blk.c). + * "Check media change" without touching any drive. + * * * TODO * - * disk change detection * synchronize multi-activity * (data + audio + ioctl + disk change, multiple drives) * implement "read all subchannel data" (96 bytes per frame) @@ -461,8 +469,8 @@ #if 0 static void mark_timeout_audio(u_long); #endif -static void sbp_read_cmd(void); -static int sbp_data(void); +static void sbp_read_cmd(struct request *req); +static int sbp_data(struct request *req); static int cmd_out(void); static int DiskInfo(void); static int sbpcd_chk_disk_change(kdev_t); @@ -510,7 +518,6 @@ static int sbpcd_debug = ((1<=0x16) return (-612); /* general failure */ - D_S[d].CD_changed=0xFF; - if (sta==0x11) return (-615); /* invalid disk change (LCS: removed) */ + if (sta==0x11) return (-ERR_DISKCHANGE); /* disk change (LCS: removed) */ if (famL_drive) - if (sta==0x12) return (-615); /* invalid disk change (inserted) */ + if (sta==0x12) return (-ERR_DISKCHANGE); /* disk change (inserted) */ return (-602); /* drive not ready */ } } @@ -1115,8 +1121,12 @@ /* 2: closed, disk in */ D_S[d].status_bits=p1_door_closed|p1_disk_in|p1_spinning|p1_disk_ok; else if (D_S[d].error_state==6) + { /* 3: closed, disk in, changed ("06 xx xx") */ D_S[d].status_bits=p1_door_closed|p1_disk_in; + D_S[d].CD_changed=0xFF; + D_S[d].diskstate_flags &= ~toc_bit; + } else if ((D_S[d].error_state!=2)||(D_S[d].b3!=0x3A)||(D_S[d].b4==0x00)) { /* 1: closed, no disk ("xx yy zz"or "02 3A 00") */ @@ -1230,6 +1240,11 @@ D_S[d].error_byte=infobuf[i]; msg(DBG_ERR,"cc_ReadError: infobuf[%d] is %d (%02X)\n",i,D_S[d].error_byte,D_S[d].error_byte); i=sta2err(infobuf[i]); + if (i==-ERR_DISKCHANGE) + { + D_S[d].CD_changed=0xFF; + D_S[d].diskstate_flags &= ~toc_bit; + } return (i); } /*==========================================================================*/ @@ -1924,7 +1939,7 @@ do { i=GetStatus(); - if ((i<0)&&(i!=-615)) return (-2); /* i!=-615 is from sta2err */ + if ((i<0)&&(i!=-ERR_DISKCHANGE)) return (-2); /* from sta2err */ if (!st_caddy_in) break; sbp_sleep(1); } @@ -4428,23 +4443,56 @@ /* * Take care of the different block sizes between cdrom and Linux. */ -static void sbp_transfer(void) +static void sbp_transfer(struct request *req) { long offs; - while ( (CURRENT->nr_sectors > 0) && - (CURRENT->sector/4 >= D_S[d].sbp_first_frame) && - (CURRENT->sector/4 <= D_S[d].sbp_last_frame) ) - { - offs = (CURRENT->sector - D_S[d].sbp_first_frame * 4) * 512; - memcpy(CURRENT->buffer, D_S[d].sbp_buf + offs, 512); - CURRENT->nr_sectors--; - CURRENT->sector++; - CURRENT->buffer += 512; + while ( (req->nr_sectors > 0) && + (req->sector/4 >= D_S[d].sbp_first_frame) && + (req->sector/4 <= D_S[d].sbp_last_frame) ) + { + offs = (req->sector - D_S[d].sbp_first_frame * 4) * 512; + memcpy(req->buffer, D_S[d].sbp_buf + offs, 512); + req->nr_sectors--; + req->sector++; + req->buffer += 512; } } /*==========================================================================*/ /* + * special end_request for sbpcd to solve CURRENT==NULL bug. (GTL) + * GTL = Gonzalo Tornaria + * + * This is a kludge so we don't need to modify end_request. + * We put the req we take out after INIT_REQUEST in the requests list, + * so that end_request will discard it. + * + * The bug could be present in other block devices, perhaps we + * should modify INIT_REQUEST and end_request instead, and + * change every block device.. + * + * Could be a race here?? Could e.g. a timer interrupt schedule() us? + * If so, we should copy end_request here, and do it right.. (or + * modify end_request and the block devices). + * + * In any case, the race here would be much small than it was, and + * I couldn't reproduce.. + * + * The race could be: suppose CURRENT==NULL. We put our req in the list, + * and we are scheduled. Other process takes over, and gets into + * do_sbpcd_request. It sees CURRENT!=NULL (it is == to our req), so + * proceeds. It ends, so CURRENT is now NULL.. Now we awake somewhere in + * end_request, but now CURRENT==NULL... oops! + * + */ +#undef DEBUG_GTL +static inline void sbpcd_end_request(struct request *req, int uptodate) { + req->next=CURRENT; + CURRENT=req; + end_request(uptodate); +} +/*==========================================================================*/ +/* * I/O request routine, called from Linux kernel. */ static void DO_SBPCD_REQUEST(void) @@ -4452,27 +4500,49 @@ u_int block; u_int nsect; int i, status_tries, data_tries; - + struct request *req; +#ifdef DEBUG_GTL + static int xx_nr=0; + int xnr; +#endif + request_loop: - INIT_REQUEST; - sti(); - - if ((CURRENT == NULL) || CURRENT->rq_status == RQ_INACTIVE) { +#ifdef DEBUG_GTL + xnr=++xx_nr; + + if(!CURRENT) + { + printk( "do_sbpcd_request[%di](NULL), Pid:%d, Time:%li\n", + xnr, current->pid, jiffies); + printk( "do_sbpcd_request[%do](NULL) end 0 (null), Time:%li\n", + xnr, jiffies); CLEAR_INTR; return; } - if (CURRENT -> sector == -1) - goto err_done; - if (CURRENT->cmd != READ) + + printk(" do_sbpcd_request[%di](%p:%ld+%ld), Pid:%d, Time:%li\n", + xnr, CURRENT, CURRENT->sector, CURRENT->nr_sectors, current->pid, jiffies); +#endif + INIT_REQUEST; + req=CURRENT; /* take out our request so no other */ + CURRENT=req->next; /* task can fuck it up GTL */ + sti(); + + if (req->rq_status == RQ_INACTIVE) + sbpcd_end_request(req, 0); + if (req -> sector == -1) + sbpcd_end_request(req, 0); + + if (req->cmd != READ) { - msg(DBG_INF, "bad cmd %d\n", CURRENT->cmd); + msg(DBG_INF, "bad cmd %d\n", req->cmd); goto err_done; } - i = MINOR(CURRENT->rq_dev); + i = MINOR(req->rq_dev); if ( (i<0) || (i>=NR_SBPCD) || (D_S[i].drv_id==-1)) { msg(DBG_INF, "do_request: bad device: %s\n", - kdevname(CURRENT->rq_dev)); + kdevname(req->rq_dev)); goto err_done; } while (busy_audio) sbp_sleep(HZ); /* wait a bit */ @@ -4481,19 +4551,23 @@ if (D_S[i].audio_state==audio_playing) goto err_done; if (d!=i) switch_drive(i); - block = CURRENT->sector; /* always numbered as 512-byte-pieces */ - nsect = CURRENT->nr_sectors; /* always counted as 512-byte-pieces */ + block = req->sector; /* always numbered as 512-byte-pieces */ + nsect = req->nr_sectors; /* always counted as 512-byte-pieces */ msg(DBG_BSZ,"read sector %d (%d sectors)\n", block, nsect); #if 0 msg(DBG_MUL,"read LBA %d\n", block/4); #endif - sbp_transfer(); + sbp_transfer(req); /* if we satisfied the request from the buffer, we're done. */ - if (CURRENT->nr_sectors == 0) + if (req->nr_sectors == 0) { - end_request(1); +#ifdef DEBUG_GTL + printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 2, Time:%li\n", + xnr, req, req->sector, req->nr_sectors, jiffies); +#endif + sbpcd_end_request(req, 1); goto request_loop; } @@ -4521,21 +4595,29 @@ break; } - sbp_read_cmd(); + sbp_read_cmd(req); sbp_sleep(0); - if (sbp_data() != 0) + if (sbp_data(req) != 0) { #if SAFE_MIXED D_S[d].has_data=2; /* is really a data disk */ #endif SAFE_MIXED - end_request(1); +#ifdef DEBUG_GTL + printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 3, Time:%li\n", + xnr, req, req->sector, req->nr_sectors, jiffies); +#endif + sbpcd_end_request(req, 1); goto request_loop; } } err_done: busy_data=0; - end_request(0); +#ifdef DEBUG_GTL + printk(" do_sbpcd_request[%do](%p:%ld+%ld) end 4 (error), Time:%li\n", + xnr, req, req->sector, req->nr_sectors, jiffies); +#endif + sbpcd_end_request(req, 0); sbp_sleep(0); /* wait a bit, try again */ goto request_loop; } @@ -4543,7 +4625,7 @@ /* * build and send the READ command. */ -static void sbp_read_cmd(void) +static void sbp_read_cmd(struct request *req) { #undef OLD @@ -4552,7 +4634,7 @@ D_S[d].sbp_first_frame=D_S[d].sbp_last_frame=-1; /* purge buffer */ D_S[d].sbp_current = 0; - block=CURRENT->sector/4; + block=req->sector/4; if (block+D_S[d].sbp_bufsiz <= D_S[d].CDsize_frm) D_S[d].sbp_read_frames = D_S[d].sbp_bufsiz; else @@ -4650,7 +4732,7 @@ * Check the completion of the read-data command. On success, read * the D_S[d].sbp_bufsiz * 2048 bytes of data from the disk into buffer. */ -static int sbp_data(void) +static int sbp_data(struct request *req) { int i=0, j=0, l, frame; u_int try=0; @@ -4913,9 +4995,9 @@ return (0); } - D_S[d].sbp_first_frame = CURRENT -> sector / 4; + D_S[d].sbp_first_frame = req -> sector / 4; D_S[d].sbp_last_frame = D_S[d].sbp_first_frame + D_S[d].sbp_read_frames - 1; - sbp_transfer(); + sbp_transfer(req); return (1); } /*==========================================================================*/ @@ -5451,15 +5533,12 @@ /* * Check if the media has changed in the CD-ROM drive. * used externally (isofs/inode.c, fs/buffer.c) - * Currently disabled (has to get "synchronized"). */ static int sbpcd_chk_disk_change(kdev_t full_dev) { - int i, st; + int i; msg(DBG_CHK,"media_check (%d) called\n", MINOR(full_dev)); - return (0); /* "busy" test necessary before we really can check */ - i=MINOR(full_dev); if ( (i<0) || (i>=NR_SBPCD) || (D_S[i].drv_id==-1) ) { @@ -5467,43 +5546,14 @@ return (-1); } - switch_drive(i); - - cc_ReadStatus(); /* command: give 1-byte status */ - st=ResponseStatus(); - msg(DBG_CHK,"media_check: %02X\n",D_S[d].status_bits); - if (st<0) - { - msg(DBG_INF,"media_check: ResponseStatus error.\n"); - return (1); /* status not obtainable */ - } - if (D_S[d].CD_changed==0xFF) msg(DBG_CHK,"media_check: \"changed\" assumed.\n"); - if (!st_spinning) msg(DBG_CHK,"media_check: motor off.\n"); - if (!st_door_closed) - { - msg(DBG_CHK,"media_check: door open.\n"); - D_S[d].CD_changed=0xFF; - } - if (!st_caddy_in) - { - msg(DBG_CHK,"media_check: no disk in drive.\n"); - D_S[d].open_count=0; - D_S[d].CD_changed=0xFF; - } - if (!st_diskok) msg(DBG_CHK,"media_check: !st_diskok.\n"); - -#if 0000 - if (D_S[d].CD_changed==0xFF) - { - D_S[d].CD_changed=1; - return (1); /* driver had a change detected before */ - } -#endif 0000 /* seems to give additional errors at the moment */ - - if (!st_diskok) return (1); /* disk not o.k. */ - if (!st_caddy_in) return (1); /* disk removed */ - if (!st_door_closed) return (1); /* door open */ - return (0); + if (D_S[i].CD_changed==0xFF) + { + D_S[i].CD_changed=0; + msg(DBG_CHK,"medium changed (drive %d)\n", i); + return (1); + } + else + return (0); } /*==========================================================================*/ /* diff -ur --new-file old/linux/drivers/char/Config.in new/linux/drivers/char/Config.in --- old/linux/drivers/char/Config.in Sat Jun 8 10:21:15 1996 +++ new/linux/drivers/char/Config.in Thu Aug 1 14:43:04 1996 @@ -66,6 +66,7 @@ else tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG fi + tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG fi bool 'Enhanced Real Time Clock Support' CONFIG_RTC endmenu diff -ur --new-file old/linux/drivers/char/Makefile new/linux/drivers/char/Makefile --- old/linux/drivers/char/Makefile Thu May 16 15:35:39 1996 +++ new/linux/drivers/char/Makefile Thu Aug 1 14:43:04 1996 @@ -40,6 +40,10 @@ ifeq ($(CONFIG_DIGI),y) L_OBJS += pcxx.o +else + ifeq ($(CONFIG_DIGI),m) + M_OBJS += pcxx.o + endif endif ifeq ($(CONFIG_CYCLADES),y) @@ -189,6 +193,16 @@ M_OBJS += scc.o endif endif + +ifeq ($(CONFIG_PCWATCHDOG),y) +M = y +L_OBJS += pcwd.o +else + ifeq ($(CONFIG_PCWATCHDOG),m) + M_OBJS += pcwd.o + MM = m + endif +endif ifeq ($(CONFIG_BAYCOM),y) L_OBJS += baycom.o diff -ur --new-file old/linux/drivers/char/baycom.c new/linux/drivers/char/baycom.c --- old/linux/drivers/char/baycom.c Thu Jun 6 13:23:55 1996 +++ new/linux/drivers/char/baycom.c Mon Jul 8 09:21:45 1996 @@ -236,7 +236,6 @@ unsigned int dcd_shreg; unsigned long descram; unsigned long scram; - unsigned char last_rxbit; }; struct modem_state { @@ -566,14 +565,14 @@ /* ---------------------------------------------------------------------- */ -static inline unsigned int tenms_to_flags(struct baycom_state *bc, +static inline unsigned int tenms_to_2flags(struct baycom_state *bc, unsigned int tenms) { switch (bc->modem_type) { case BAYCOM_MODEM_SER12: - return tenms * 12 / 8; + return tenms * 3 / 4; case BAYCOM_MODEM_PAR96: - return tenms * 12; + return tenms * 6; default: return 0; } @@ -581,8 +580,7 @@ /* ---------------------------------------------------------------------- */ /* - * The HDLC routines could be more efficient; they could take more than - * one bit per call + * The HDLC routines */ static inline int hdlc_rx_add_bytes(struct baycom_state *bc, @@ -699,7 +697,7 @@ &bc->hdlc_tx.len); if (!bc->hdlc_tx.bp || !bc->hdlc_tx.len) { bc->hdlc_tx.tx_state = 1; - bc->hdlc_tx.numflags = tenms_to_flags + bc->hdlc_tx.numflags = tenms_to_2flags (bc, bc->ch_params.tx_tail); break; } @@ -779,9 +777,10 @@ if ((random_num() % 256) > bc->ch_params.ppersist) return; } - bc->hdlc_tx.ptt = 1; bc->hdlc_tx.tx_state = 0; - bc->hdlc_tx.numflags = tenms_to_flags(bc, bc->ch_params.tx_delay); + bc->hdlc_tx.numflags = tenms_to_2flags(bc, bc->ch_params.tx_delay); + bc->hdlc_tx.numbits = bc->hdlc_tx.bitbuf = bc->hdlc_tx.bitstream = 0; + bc->hdlc_tx.ptt = 1; bc->stat.ptt_keyed++; } @@ -1162,7 +1161,7 @@ ser12_set_divisor(bc, (bc->options & BAYCOM_OPTIONS_SOFTDCD) ? 4 : 6); outb(0x0d, MCR(bc->iobase)); outb(0, IER(bc->iobase)); - if (request_irq(bc->irq, baycom_ser12_interrupt, 0, + if (request_irq(bc->irq, baycom_ser12_interrupt, SA_INTERRUPT, "baycom_ser12", bc)) return -EBUSY; /* @@ -1212,7 +1211,7 @@ { register struct baycom_state *bc = (struct baycom_state *)dev_id; int i; - unsigned int data, rawdata, mask, mask2; + unsigned int data, descx, mask, mask2; if (!bc || bc->magic != BAYCOM_MAGIC) return; @@ -1270,8 +1269,7 @@ /* * do receiver; differential decode and descramble on the fly */ - for(rawdata = data = i = 0; i < PAR96_BURSTBITS; i++) { - unsigned int descx; + for(data = i = 0; i < PAR96_BURSTBITS; i++) { bc->modem.par96.descram = (bc->modem.par96.descram << 1); if (inb(LPT_STATUS(bc->iobase)) & PAR96_RXBIT) bc->modem.par96.descram |= 1; @@ -1281,14 +1279,9 @@ outb(PAR97_POWER | PAR96_PTT, LPT_DATA(bc->iobase)); descx ^= ((descx >> PAR96_DESCRAM_TAPSH1) ^ (descx >> PAR96_DESCRAM_TAPSH2)); - if (descx & 1) - bc->modem.par96.last_rxbit = - !bc->modem.par96.last_rxbit; data >>= 1; - if (bc->modem.par96.last_rxbit) + if (!(descx & 1)) data |= 0x8000; - rawdata <<= 1; - rawdata |= !(descx & 1); outb(PAR97_POWER | PAR96_PTT | PAR96_BURST, LPT_DATA(bc->iobase)); } @@ -1304,26 +1297,26 @@ * do DCD algorithm */ if (bc->options & BAYCOM_OPTIONS_SOFTDCD) { - bc->modem.par96.dcd_shreg = (bc->modem.par96.dcd_shreg << 16) - | rawdata; + bc->modem.par96.dcd_shreg = (bc->modem.par96.dcd_shreg >> 16) + | (data << 16); /* search for flags and set the dcd counter appropriately */ - for(mask = 0x7f8000, mask2 = 0x3f0000, i = 0; - i < PAR96_BURSTBITS; i++, mask >>= 1, mask2 >>= 1) + for(mask = 0x1fe00, mask2 = 0xfc00, i = 0; + i < PAR96_BURSTBITS; i++, mask <<= 1, mask2 <<= 1) if ((bc->modem.par96.dcd_shreg & mask) == mask2) bc->modem.par96.dcd_count = BAYCOM_MAXFLEN+4; /* check for abort/noise sequences */ - for(mask = 0x3f8000, mask2 = 0x3f8000, i = 0; - i < PAR96_BURSTBITS; i++, mask >>= 1, mask2 >>= 1) - if ((bc->modem.par96.dcd_shreg & mask) == mask2) - if (bc->modem.par96.dcd_count >= 0) - bc->modem.par96.dcd_count -= - BAYCOM_MAXFLEN-10; + for(mask = 0x1fe00, mask2 = 0x1fe00, i = 0; + i < PAR96_BURSTBITS; i++, mask <<= 1, mask2 <<= 1) + if (((bc->modem.par96.dcd_shreg & mask) == mask2) && + (bc->modem.par96.dcd_count >= 0)) + bc->modem.par96.dcd_count -= BAYCOM_MAXFLEN-10; /* decrement and set the dcd variable */ if (bc->modem.par96.dcd_count >= 0) bc->modem.par96.dcd_count -= 2; bc->modem.dcd = bc->modem.par96.dcd_count > 0; } else { - bc->modem.dcd = !!(inb(LPT_STATUS(bc->iobase)) & PAR96_DCD); + bc->modem.dcd = !!(inb(LPT_STATUS(bc->iobase)) + & PAR96_DCD); } if (--bc->modem.arb_divider <= 0) { #ifdef BAYCOM_USE_BH @@ -1407,7 +1400,7 @@ outb(0, LPT_CONTROL(bc->iobase)); /* disable interrupt */ /* switch off PTT */ outb(PAR96_PTT | PAR97_POWER, LPT_DATA(bc->iobase)); - if (request_irq(bc->irq, baycom_par96_interrupt, 0, + if (request_irq(bc->irq, baycom_par96_interrupt, SA_INTERRUPT, "baycom_par96", bc)) return -EBUSY; outb(LPT_IRQ_ENABLE, LPT_CONTROL(bc->iobase)); /* enable interrupt */ @@ -1593,6 +1586,10 @@ } if (!bc->kiss_decode.dec_state) return; + if (ch == KISS_FESC) { + bc->kiss_decode.escaped = 1; + return; + } if (bc->kiss_decode.wr >= sizeof(bc->kiss_decode.pkt_buf)) { bc->kiss_decode.wr = 0; bc->kiss_decode.dec_state = 0; @@ -2276,6 +2273,7 @@ printk(KERN_INFO "baycom: cleanup_module called\n"); + disable_bh(BAYCOM_BH); if (tty_unregister_driver(&baycom_driver)) printk(KERN_WARNING "baycom: failed to unregister tty " "driver\n"); @@ -2327,20 +2325,3 @@ #endif /* MODULE */ /* --------------------------------------------------------------------- */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 8 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -8 - * c-argdecl-indent: 8 - * c-label-offset: -8 - * c-continued-statement-offset: 8 - * c-continued-brace-offset: 0 - * End: - */ diff -ur --new-file old/linux/drivers/char/console.c new/linux/drivers/char/console.c --- old/linux/drivers/char/console.c Thu Aug 29 16:32:45 1996 +++ new/linux/drivers/char/console.c Thu Aug 29 16:33:32 1996 @@ -306,7 +306,7 @@ int vc_allocate(unsigned int i) /* return 0 on success */ { if (i >= MAX_NR_CONSOLES) - return -ENODEV; + return -ENXIO; if (!vc_cons[i].d) { long p, q; diff -ur --new-file old/linux/drivers/char/cp437.uni new/linux/drivers/char/cp437.uni --- old/linux/drivers/char/cp437.uni Tue Jun 13 09:47:47 1995 +++ new/linux/drivers/char/cp437.uni Mon Jul 15 08:57:04 1996 @@ -28,8 +28,8 @@ 0x0d U+266a 0x0e U+266b 0x0f U+263c -0x10 U+25ba -0x11 U+25c4 +0x10 U+25b6 U+25ba +0x11 U+25c0 U+25c4 0x12 U+2195 0x13 U+203c 0x14 U+00b6 diff -ur --new-file old/linux/drivers/char/cyclades.c new/linux/drivers/char/cyclades.c --- old/linux/drivers/char/cyclades.c Wed Apr 24 06:33:36 1996 +++ new/linux/drivers/char/cyclades.c Thu Aug 1 14:31:04 1996 @@ -1,5 +1,5 @@ static char rcsid[] = -"$Revision: 1.36.3.7 $$Date: 1996/04/19 21:06:18 $"; +"$Revision: 1.36.3.7A $$Date: 1996/07/27 10:25:50 $"; /* * linux/drivers/char/cyclades.c * @@ -2250,6 +2250,13 @@ (unsigned long *) arg); break; case TIOCSSOFTCAR: + error = verify_area(VERIFY_READ, (void *) arg + ,sizeof(unsigned long *)); + if (error) { + ret_val = error; + break; + } + arg = get_fs_long((unsigned long *) arg); tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | @@ -2275,6 +2282,12 @@ (struct serial_struct *) arg); break; case TIOCSSERIAL: + error = verify_area(VERIFY_READ, (void *) arg + ,sizeof(struct serial_struct)); + if (error){ + ret_val = error; + break; + } ret_val = set_serial_info(info, (struct serial_struct *) arg); break; @@ -2646,6 +2659,8 @@ return retval; } + MOD_INC_USE_COUNT; + retval = block_til_ready(tty, filp, info); if (retval) { #ifdef SERIAL_DEBUG_OPEN @@ -2661,7 +2676,6 @@ #ifdef SERIAL_DEBUG_OPEN printk("cy_open done\n");/**/ #endif - MOD_INC_USE_COUNT; return 0; } /* cy_open */ diff -ur --new-file old/linux/drivers/char/keyboard.c new/linux/drivers/char/keyboard.c --- old/linux/drivers/char/keyboard.c Mon May 13 06:36:19 1996 +++ new/linux/drivers/char/keyboard.c Thu Jul 25 19:24:49 1996 @@ -18,6 +18,7 @@ */ #define KEYBOARD_IRQ 1 +#define DISABLE_KBD_DURING_INTERRUPTS 0 #include #include @@ -69,14 +70,6 @@ #define KBD_DEFLOCK 0 #endif -/* - * The default IO slowdown is doing 'inb()'s from 0x61, which should be - * safe. But as that is the keyboard controller chip address, we do our - * slowdowns here by doing short jumps: the keyboard controller should - * be able to keep up - */ -#define REALLY_SLOW_IO -#define SLOW_IO_BY_JUMPING #include #include @@ -337,48 +330,31 @@ e0_keys[scancode - 128]; } -static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs) +#if DISABLE_KBD_DURING_INTERRUPTS +#define disable_keyboard() do { send_cmd(0xAD); kb_wait(); } while (0) +#define enable_keyboard() send_cmd(0xAE) +#else +#define disable_keyboard() /* nothing */ +#define enable_keyboard() /* nothing */ +#endif + +static void handle_scancode(unsigned char scancode) { - unsigned char scancode, keycode; + unsigned char keycode; static unsigned int prev_scancode = 0; /* remember E0, E1 */ char up_flag; /* 0 or 0200 */ char raw_mode; - int status; - pt_regs = regs; - send_cmd(0xAD); /* disable keyboard */ - kb_wait(); - status = inb_p(0x64); - if ((status & kbd_read_mask) != 0x01) { - /* - * On some platforms (Alpha XL for one), the init code may leave - * an interrupt hanging, yet with status indicating no data. - * After making sure that there's no data indicated and its not a - * mouse interrupt, we will read the data register to clear it. - * If we don't do this, the data reg stays full and will not - * allow new data or interrupt from the keyboard. Sigh... - */ - if (!(status & 0x21)) { /* neither ODS nor OBF */ - scancode = inb(0x60); /* read data anyway */ -#if 0 - printk(KERN_DEBUG "keyboard: status 0x%x mask 0x%x data 0x%x\n", - status, kbd_read_mask, scancode); -#endif - } - goto end_kbd_intr; - } - scancode = inb(0x60); - mark_bh(KEYBOARD_BH); if (reply_expected) { /* 0xfa, 0xfe only mean "acknowledge", "resend" for most keyboards */ /* but they are the key-up scancodes for PF6, PF10 on a FOCUS 9000 */ reply_expected = 0; if (scancode == 0xfa) { acknowledge = 1; - goto end_kbd_intr; + return; } else if (scancode == 0xfe) { resend = 1; - goto end_kbd_intr; + return; } /* strange ... */ reply_expected = 1; @@ -392,7 +368,7 @@ printk(KERN_INFO "keyboard buffer overflow\n"); #endif prev_scancode = 0; - goto end_kbd_intr; + return; } do_poke_blanked_console = 1; mark_bh(CONSOLE_BH); @@ -417,12 +393,12 @@ #endif #endif prev_scancode = 0; - goto end_kbd_intr; + return; } if (scancode == 0xe0 || scancode == 0xe1) { prev_scancode = scancode; - goto end_kbd_intr; + return; } /* @@ -439,7 +415,7 @@ if (prev_scancode != 0xe0) { if (prev_scancode == 0xe1 && scancode == 0x1d) { prev_scancode = 0x100; - goto end_kbd_intr; + return; } else if (prev_scancode == 0x100 && scancode == 0x45) { keycode = E1_PAUSE; prev_scancode = 0; @@ -449,7 +425,7 @@ printk(KERN_INFO "keyboard: unknown e1 escape sequence\n"); #endif prev_scancode = 0; - goto end_kbd_intr; + return; } } else { prev_scancode = 0; @@ -467,7 +443,7 @@ * So, we should also ignore the latter. - aeb@cwi.nl */ if (scancode == 0x2a || scancode == 0x36) - goto end_kbd_intr; + return; if (e0_keys[scancode]) keycode = e0_keys[scancode]; @@ -477,7 +453,7 @@ printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n", scancode); #endif - goto end_kbd_intr; + return; } } } else if (scancode >= SC_LIM) { @@ -500,7 +476,7 @@ " - ignored\n", scancode); #endif } - goto end_kbd_intr; + return; } } else keycode = scancode; @@ -526,12 +502,12 @@ rep = set_bit(keycode, key_down); if (raw_mode) - goto end_kbd_intr; + return; if (kbd->kbdmode == VC_MEDIUMRAW) { /* soon keycodes will require more than one byte */ put_queue(keycode + up_flag); - goto end_kbd_intr; + return; } /* @@ -592,9 +568,32 @@ #endif } } +} + +static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned char status; -end_kbd_intr: - send_cmd(0xAE); /* enable keyboard */ + pt_regs = regs; + disable_keyboard(); + + status = inb_p(0x64); + do { + unsigned char scancode; + + /* mouse data? */ + if (status & kbd_read_mask & 0x20) + break; + + scancode = inb(0x60); + if (status & 0x01) + handle_scancode(scancode); + + status = inb(0x64); + } while (status & 0x01); + + mark_bh(KEYBOARD_BH); + enable_keyboard(); } static void put_queue(int ch) diff -ur --new-file old/linux/drivers/char/lp.c new/linux/drivers/char/lp.c --- old/linux/drivers/char/lp.c Mon May 6 12:20:19 1996 +++ new/linux/drivers/char/lp.c Tue Jul 2 18:08:41 1996 @@ -322,9 +322,9 @@ unsigned int irq; if (minor >= LP_NO) - return -ENODEV; + return -ENXIO; if ((LP_F(minor) & LP_EXIST) == 0) - return -ENODEV; + return -ENXIO; if (LP_F(minor) & LP_BUSY) return -EBUSY; diff -ur --new-file old/linux/drivers/char/mem.c new/linux/drivers/char/mem.c --- old/linux/drivers/char/mem.c Thu Apr 25 12:27:42 1996 +++ new/linux/drivers/char/mem.c Thu Aug 1 14:43:04 1996 @@ -176,6 +176,8 @@ for (left = count; left > 0; left--) { put_user(0,buf); buf++; + if (need_resched) + schedule(); } return count; } @@ -358,7 +360,7 @@ filp->f_op = &urandom_fops; break; default: - return -ENODEV; + return -ENXIO; } if (filp->f_op && filp->f_op->open) return filp->f_op->open(inode,filp); @@ -398,6 +400,9 @@ #endif #if CONFIG_QIC02_TAPE qic02_tape_init(); +#endif +#ifdef CONFIG_PCWATCHDOG + pcwatchdog_init(); #endif #if CONFIG_ISDN isdn_init(); diff -ur --new-file old/linux/drivers/char/n_tty.c new/linux/drivers/char/n_tty.c --- old/linux/drivers/char/n_tty.c Wed Apr 24 08:13:04 1996 +++ new/linux/drivers/char/n_tty.c Wed Jul 24 09:49:53 1996 @@ -201,7 +201,7 @@ tty->read_head = tty->canon_head; return; } - if (!L_ECHOK(tty) || !L_ECHOKE(tty)) { + if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) { tty->read_cnt -= ((tty->read_head - tty->canon_head) & (N_TTY_BUF_SIZE - 1)); tty->read_head = tty->canon_head; @@ -236,7 +236,7 @@ tty->erasing = 1; } echo_char(c, tty); - } else if (!L_ECHOE(tty)) { + } else if (kill_type == ERASE && !L_ECHOE(tty)) { echo_char(ERASE_CHAR(tty), tty); } else if (c == '\t') { unsigned int col = tty->canon_column; @@ -290,11 +290,11 @@ finish_erasing(tty); } -static void isig(int sig, struct tty_struct *tty) +static inline void isig(int sig, struct tty_struct *tty, int flush) { if (tty->pgrp > 0) kill_pg(tty->pgrp, sig, 1); - if (!L_NOFLSH(tty)) { + if (flush || !L_NOFLSH(tty)) { n_tty_flush_buffer(tty); if (tty->driver.flush_buffer) tty->driver.flush_buffer(tty); @@ -306,7 +306,7 @@ if (I_IGNBRK(tty)) return; if (I_BRKINT(tty)) { - isig(SIGINT, tty); + isig(SIGINT, tty, 1); return; } if (I_PARMRK(tty)) { @@ -340,8 +340,10 @@ put_tty_queue('\377', tty); put_tty_queue('\0', tty); put_tty_queue(c, tty); - } else + } else if (I_INPCK(tty)) put_tty_queue('\0', tty); + else + put_tty_queue(c, tty); wake_up_interruptible(&tty->read_wait); } @@ -415,17 +417,17 @@ } } if (L_ISIG(tty)) { - if (c == INTR_CHAR(tty)) { - isig(SIGINT, tty); - return; - } - if (c == QUIT_CHAR(tty)) { - isig(SIGQUIT, tty); - return; - } + int signal; + signal = SIGINT; + if (c == INTR_CHAR(tty)) + goto send_signal; + signal = SIGQUIT; + if (c == QUIT_CHAR(tty)) + goto send_signal; + signal = SIGTSTP; if (c == SUSP_CHAR(tty)) { - if (!is_orphaned_pgrp(tty->pgrp)) - isig(SIGTSTP, tty); +send_signal: + isig(signal, tty, 0); return; } } diff -ur --new-file old/linux/drivers/char/pcwd.c new/linux/drivers/char/pcwd.c --- old/linux/drivers/char/pcwd.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/char/pcwd.c Thu Aug 1 15:12:26 1996 @@ -0,0 +1,331 @@ +/* + * PC Watchdog Driver + * by Ken Hollis (khollis@bitgate.com) + * + * Permission granted from Simon Machell (73244.1270@compuserve.com) + * Written for the Linux Kernel, and GPLed by Ken Hollis + * + * 960107 Added request_region routines, modulized the whole thing. + * 960108 Fixed end-of-file pointer (Thanks to Dan Hollis), added + * WD_TIMEOUT define. + * 960216 Added eof marker on the file, and changed verbose messages. + * 960716 Made functional and cosmetic changes to the source for + * inclusion in Linux 2.0.x kernels, thanks to Alan Cox. + * 960717 Removed read/seek routines, replaced with ioctl. Also, added + * check_region command due to Alan's suggestion. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define WD_VER "0.41 (07/17/96)" +#define WD_MINOR 130 /* Minor device number */ + +#define WD_TIMEOUT 3 /* 1 1/2 seconds for a timeout */ + +#define WD_TIMERRESET_PORT1 0x270 /* Reset port - first choice */ +#define WD_TIMERRESET_PORT2 0x370 /* Reset port - second choice */ +#define WD_CTLSTAT_PORT1 0x271 /* Control port - first choice */ +#define WD_CTLSTAT_PORT2 0x371 /* Control port - second choice */ +#define WD_PORT_EXTENT 2 /* Takes up two addresses */ + +#define WD_WDRST 0x01 /* Previously reset state */ +#define WD_T110 0x02 /* Temperature overheat sense */ +#define WD_HRTBT 0x04 /* Heartbeat sense */ +#define WD_RLY2 0x08 /* External relay triggered */ +#define WD_SRLY2 0x80 /* Software external relay triggered */ + +static int current_ctlport, current_readport; +static int is_open, is_eof; + +int pcwd_checkcard(void) +{ + int card_dat, prev_card_dat, found = 0, count = 0, done = 0; + + /* As suggested by Alan Cox */ + if (check_region(current_ctlport, WD_PORT_EXTENT)) { + printk("pcwd: Port 0x%x unavailable.\n", current_ctlport); + return 0; + } + + card_dat = 0x00; + prev_card_dat = 0x00; + + prev_card_dat = inb(current_readport); + + while(count < WD_TIMEOUT) { +#ifdef DEBUG + printk("pcwd: Run #%d on port 0x%03x\n", count, current_readport); +#endif + + /* Read the raw card data from the port, and strip off the + first 4 bits */ + + card_dat = inb_p(current_readport); + card_dat &= 0x000F; + + /* Sleep 1/2 second (or 500000 microseconds :) */ + + udelay(500000L); + done = 0; + + /* 0x0F usually means that no card data is present, or the card + is not installed on this port. If 0x0F is present here, it's + normally safe to assume there's no card at that base address. */ + + if (card_dat == 0x0F) { + count++; + done = 1; + +#ifdef DEBUG + printk("pcwd: I show nothing on this port.\n"); +#endif + } + + /* If there's a heart beat in both instances, then this means we + found our card. This also means that either the card was + previously reset, or the computer was power-cycled. */ + + if ((card_dat & WD_HRTBT) && (prev_card_dat & WD_HRTBT) && + (!done)) { + found = 1; + done = 1; +#ifdef DEBUG + printk("pcwd: I show alternate heart beats. Card detected.\n"); +#endif + break; + } + + /* If the card data is exactly the same as the previous card data, + it's safe to assume that we should check again. The manual says + that the heart beat will change every second (or the bit will + toggle), and this can be used to see if the card is there. If + the card was powered up with a cold boot, then the card will + not start blinking until 2.5 minutes after a reboot, so this + bit will stay at 1. */ + + if ((card_dat == prev_card_dat) && (!done)) { + count++; +#ifdef DEBUG + printk("pcwd: The card data is exactly the same (possibility).\n"); +#endif + done = 1; + } + + /* If the card data is toggling any bits, this means that the heart + beat was detected, or something else about the card is set. */ + + if ((card_dat != prev_card_dat) && (!done)) { + done = 1; + found = 1; +#ifdef DEBUG + printk("pcwd: I show alternate heart beats. Card detected.\n"); +#endif + break; + } + + /* Otherwise something else strange happened. */ + + if (!done) + count++; + } + + return((found) ? 1 : 0); +} + +void pcwd_showprevstate(void) +{ + int card_status = 0x0000; + + card_status = inb(current_readport); + + if (card_status & WD_WDRST) + printk("pcwd: Previous reboot was caused by the card.\n"); + + if (card_status & WD_T110) + printk("pcwd: CPU overheat sense\n"); +} + +static int pcwd_return_data(void) +{ + return(inb(current_readport)); +} + +static int pcwd_write(struct inode *inode, struct file *file, const char *data, + int len) +{ + int wdrst_stat; + + if (!is_open) + return -EIO; + +#ifdef DEBUG + printk("pcwd: write request\n"); +#endif + + wdrst_stat = inb_p(current_readport); + wdrst_stat &= 0x0F; + + wdrst_stat |= WD_WDRST; + + outb_p(wdrst_stat, current_ctlport); + + return(1); +} + +static int pcwd_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int i, cdat, rv; + + switch(cmd) { + default: + return -ENOIOCTLCMD; + + case PCWD_GETSTAT: + i = verify_area(VERIFY_WRITE, (void*) arg, sizeof(int)); + if (i) + return i; + else { + cdat = pcwd_return_data(); + rv = 0; + + if (cdat & WD_WDRST) + rv |= 0x01; + + if (cdat & WD_T110) + rv |= 0x02; + + put_user(rv, (int *) arg); + return 0; + } + break; + + case PCWD_PING: + pcwd_write(NULL, NULL, NULL, 1); /* Is this legal? */ + break; + } + + return 0; +} + +static int pcwd_open(struct inode *ino, struct file *filep) +{ +#ifdef DEBUG + printk("pcwd: open request\n"); +#endif + + MOD_INC_USE_COUNT; + is_eof = 0; + return(0); +} + +static void pcwd_close(struct inode *ino, struct file *filep) +{ +#ifdef DEBUG + printk("pcwd: close request\n"); +#endif + + MOD_DEC_USE_COUNT; +} + +struct file_operations pcwd_fops = { + NULL, /* Seek */ + NULL, /* Read */ + pcwd_write, /* Write */ + NULL, /* Readdir */ + NULL, /* Select */ + pcwd_ioctl, /* IOctl */ + NULL, /* MMAP */ + pcwd_open, /* Open */ + pcwd_close, /* Close */ + NULL +}; + +static struct miscdevice pcwd_miscdev = { + WD_MINOR, + "pcwatchdog", + &pcwd_fops +}; + +#ifdef MODULE +int init_module(void) +#else +int pcwatchdog_init(void) +#endif +{ +#ifdef DEBUG + printk("pcwd: Success.\n"); +#endif + printk("pcwd: v%s Ken Hollis (khollis@bitgate.com)\n", WD_VER); + +#ifdef DEBUG + printk("pcwd: About to perform card autosense loop.\n"); +#endif + + is_eof = 0; + is_open = 0; + + current_ctlport = WD_TIMERRESET_PORT1; + current_readport = WD_CTLSTAT_PORT1; + + if (!pcwd_checkcard()) { +#ifdef DEBUG + printk("pcwd: Trying port 0x370.\n"); +#endif + + current_ctlport = WD_TIMERRESET_PORT2; + current_readport = WD_CTLSTAT_PORT2; + + if (!pcwd_checkcard()) { + printk("pcwd: No card detected.\n"); + return(-EIO); + } else + printk("pcwd: Port available at 0x370.\n"); + } else + printk("pcwd: Port available at 0x270.\n"); + + pcwd_showprevstate(); + +#ifdef DEBUG + printk("pcwd: Requesting region entry\n"); +#endif + + request_region(current_ctlport, WD_PORT_EXTENT, "PCWD (Berkshire)"); + +#ifdef DEBUG + printk("pcwd: character device creation.\n"); +#endif + + misc_register(&pcwd_miscdev); + + return 0; +} + +#ifdef MODULE +void cleanup_module(void) +{ + misc_deregister(&pcwd_miscdev); + release_region(current_ctlport, 2); +#ifdef DEBUG + printk("pcwd: Cleanup successful.\n"); +#endif +} +#endif diff -ur --new-file old/linux/drivers/char/pcxx.c new/linux/drivers/char/pcxx.c --- old/linux/drivers/char/pcxx.c Sun May 19 14:24:50 1996 +++ new/linux/drivers/char/pcxx.c Thu Aug 1 14:40:32 1996 @@ -30,8 +30,13 @@ * variable handling, instead of using the old pcxxconfig.h * 1.5.6 April 16, 1996 Christoph Lameter: Pointer cleanup, macro cleanup. * Call out devices changed to /dev/cudxx. + * 1.5.7 July 22, 1996 Martin Mares: CLOCAL fix, pcxe_table clearing. + * David Nugent: Bug in pcxe_open. + * Brian J. Murrell: Modem Control fixes, Majors correctly assigned * */ +#undef MODULE +/* Module code is broken right now. Don't enable this unless you want to fix it */ #undef SPEED_HACK /* If you define SPEED_HACK then you get the following Baudrate translation @@ -41,6 +46,7 @@ some distributions like Slackware 3.0 don't like these high baudrates. */ +#include #include #include #include @@ -59,18 +65,24 @@ #include #include #include + +#ifndef MODULE + +/* is* routines not available in modules +** the need for this should go away when probing is done. :-) +** brian@ilinx.com +*/ + #include +#endif #include #include #include #include -#define VERSION "1.5.6" -static char *banner = "Digiboard PC/X{i,e,eve} driver v1.5.6. Christoph Lameter ."; - -/*#define DEFAULT_HW_FLOW 1 */ -/*#define DEBUG_IOCTL */ +#define VERSION "1.5.7" +static char *banner = "Digiboard PC/X{i,e,eve} driver v1.5.7"; #include "digi.h" #include "fep.h" @@ -145,6 +157,62 @@ #define TZ_BUFSZ 4096 +/* function definitions */ +#ifdef MODULE +int init_module(void); +void cleanup_module(void); + +/* + * Loadable module initialization stuff. + */ + +int init_module() +{ + + return pcxe_init(); + +} + +/*****************************************************************************/ + +void cleanup_module() +{ + + unsigned long flags; + int crd, i; + int e1, e2; + struct board_info *bd; + struct channel *ch; + + printk(KERN_INFO "Unloading PC/Xx: version %s\n", VERSION); + + save_flags(flags); + cli(); + timer_active &= ~(1 << DIGI_TIMER); + timer_table[DIGI_TIMER].fn = NULL; + timer_table[DIGI_TIMER].expires = 0; + + if ((e1 = tty_unregister_driver(&pcxe_driver))) + printk("SERIAL: failed to unregister serial driver (%d)\n", e1); + if ((e2 = tty_unregister_driver(&pcxe_callout))) + printk("SERIAL: failed to unregister callout driver (%d)\n",e2); + + for(crd=0; crd < numcards; crd++) { + bd = &boards[crd]; + ch = digi_channels+bd->first_minor; + for(i=0; i < bd->numports; i++, ch++) { + kfree(ch->tmp_buf); + } + release_region(bd->port, 4); + } + kfree(digi_channels); + kfree(pcxe_termios_locked); + kfree(pcxe_termios); + kfree(pcxe_table); + restore_flags(flags); +} +#endif + static inline struct channel *chan(register struct tty_struct *tty) { if (tty) { @@ -289,7 +357,6 @@ } -/* static ???why static??? */ int pcxe_open(struct tty_struct *tty, struct file * filp) { volatile struct board_chan *bc; @@ -309,7 +376,7 @@ for(boardnum=0;boardnum= boards[boardnum].first_minor) && - (line <= boards[boardnum].first_minor + boards[boardnum].numports)) + (line < boards[boardnum].first_minor + boards[boardnum].numports)) break; if(boardnum >= numcards || boards[boardnum].status == DISABLED || @@ -325,6 +392,8 @@ return(-ENODEV); } + /* flag the kernel that there is somebody using this guy */ + MOD_INC_USE_COUNT; /* * If the device is in the middle of being closed, then block * until it's done, and then try again. @@ -393,6 +462,13 @@ return -EBUSY; } else { + /* this has to be set in order for the "block until + * CD" code to work correctly. i'm not sure under + * what circumstances asyncflags should be set to + * ASYNC_NORMAL_ACTIVE though + * brian@ilinx.com + */ + ch->asyncflags |= ASYNC_NORMAL_ACTIVE; if ((retval = pcxx_waitcarrier(tty, filp, ch)) != 0) return retval; } @@ -460,11 +536,26 @@ cli(); if(tty_hung_up_p(filp)) { + /* flag that somebody is done with this module */ + MOD_DEC_USE_COUNT; restore_flags(flags); return; } + /* this check is in serial.c, it won't hurt to do it here too */ + if ((tty->count == 1) && (info->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. Info->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk("pcxe_close: bad serial port count; tty->count is 1, info->count is %d\n", info->count); + info->count = 1; + } if (info->count-- > 1) { restore_flags(flags); + MOD_DEC_USE_COUNT; return; } if (info->count < 0) { @@ -495,6 +586,13 @@ tty->closing = 0; info->event = 0; info->tty = NULL; +#ifndef MODULE +/* ldiscs[] is not available in a MODULE +** worth noting that while I'm not sure what this hunk of code is supposed +** to do, it is not present in the serial.c driver. Hmmm. If you know, +** please send me a note. brian@ilinx.com +** Dont know either what this is supposed to do clameter@waterf.org. +*/ if(tty->ldisc.num != ldiscs[N_TTY].num) { if(tty->ldisc.close) (tty->ldisc.close)(tty); @@ -503,6 +601,7 @@ if(tty->ldisc.open) (tty->ldisc.open)(tty); } +#endif if(info->blocked_open) { if(info->close_delay) { current->state = TASK_INTERRUPTIBLE; @@ -514,6 +613,7 @@ info->asyncflags &= ~(ASYNC_NORMAL_ACTIVE| ASYNC_CALLOUT_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); + MOD_DEC_USE_COUNT; restore_flags(flags); } } @@ -562,9 +662,12 @@ cli(); globalwinon(ch); head = bc->tin & (size - 1); - tail = bc->tout; - if (tail != bc->tout) - tail = bc->tout; + /* It seems to be necessary to make sure that the value is stable here somehow + This is a rather odd pice of code here. */ + do + { tail = bc->tout; + } while (tail != bc->tout); + tail &= (size - 1); stlen = (head >= tail) ? (size - (head - tail) - 1) : (tail - head - 1); count = MIN(stlen, count); @@ -882,6 +985,11 @@ case 4: t2 = str; +#ifndef MODULE +/* is* routines not available in modules +** the need for this should go away when probing is done. :-) +** brian@ilinx.com +*/ while (isdigit(*t2)) t2++; @@ -890,12 +998,18 @@ printk("PC/Xx: Invalid port count %s\n", str); return; } +#endif board.numports = simple_strtoul(str, NULL, 0); last = i; break; case 5: +#ifndef MODULE +/* is* routines not available in modules +** the need for this should go away when probing is done. :-) +** brian@ilinx.com +*/ t2 = str; while (isxdigit(*t2)) t2++; @@ -905,12 +1019,18 @@ printk("PC/Xx: Invalid port count %s\n", str); return; } +#endif board.port = simple_strtoul(str, NULL, 16); last = i; break; case 6: +#ifndef MODULE +/* is* routines not available in modules +** the need for this should go away when probing is done. :-) +** brian@ilinx.com +*/ t2 = str; while (isxdigit(*t2)) t2++; @@ -920,6 +1040,7 @@ printk("PC/Xx: Invalid memory base %s\n", str); return; } +#endif board.membase = simple_strtoul(str, NULL, 16); last = i; @@ -958,10 +1079,6 @@ int pcxe_init(void) { -#if 0 - ulong save_loops_per_sec; -#endif - ulong flags, memory_seg=0, memory_size; int lowwater, i, crd, shrinkmem=0, topwin = 0xff00L, botwin=0x100L; unchar *fepos, *memaddr, *bios, v; @@ -998,6 +1115,7 @@ pcxe_table = kmalloc(sizeof(struct tty_struct *) * nbdevs, GFP_KERNEL); if (!pcxe_table) panic("Unable to allocate pcxe_table struct"); + memset(pcxe_table, 0, sizeof(struct tty_struct *) * nbdevs); pcxe_termios = kmalloc(sizeof(struct termios *) * nbdevs, GFP_KERNEL); if (!pcxe_termios) @@ -1007,7 +1125,6 @@ if (!pcxe_termios_locked) panic("Unable to allocate pcxe_termios_locked struct"); - init_bh(DIGI_BH,do_pcxe_bh); enable_bh(DIGI_BH); @@ -1016,7 +1133,7 @@ memset(&pcxe_driver, 0, sizeof(struct tty_driver)); pcxe_driver.magic = TTY_DRIVER_MAGIC; - pcxe_driver.name = "cud"; + pcxe_driver.name = "ttyD"; pcxe_driver.major = DIGI_MAJOR; pcxe_driver.minor_start = 0; @@ -1025,7 +1142,7 @@ pcxe_driver.type = TTY_DRIVER_TYPE_SERIAL; pcxe_driver.subtype = SERIAL_TYPE_NORMAL; pcxe_driver.init_termios = tty_std_termios; - pcxe_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL; + pcxe_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL; pcxe_driver.flags = TTY_DRIVER_REAL_RAW; pcxe_driver.refcount = &pcxe_refcount; @@ -1050,22 +1167,10 @@ pcxe_driver.hangup = pcxe_hangup; pcxe_callout = pcxe_driver; - pcxe_callout.name = "ttyD"; + pcxe_callout.name = "cud"; pcxe_callout.major = DIGICU_MAJOR; pcxe_callout.subtype = SERIAL_TYPE_CALLOUT; - pcxe_callout.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL; - -#if 0 - -/* strangely enough, this is FALSE */ - - /* - * loops_per_sec hasn't been set at this point :-(, so fake it out... - * I set it so that I can use the __delay() function. - */ - save_loops_per_sec = loops_per_sec; - loops_per_sec = 13L*500000L; -#endif + pcxe_callout.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; save_flags(flags); cli(); @@ -1346,6 +1451,10 @@ ch->normal_termios = pcxe_driver.init_termios; ch->open_wait = 0; ch->close_wait = 0; + /* zero out flags as it is unassigned at this point + * brian@ilinx.com + */ + ch->asyncflags = 0; } printk("PC/Xx: %s (%s) I/O=0x%x Mem=0x%lx Ports=%d\n", @@ -1610,7 +1719,7 @@ if (cflag & B115200) res|=1; } else ch->digiext.digi_flags &= ~DIGI_FAST; - res |= cflag & (CBAUD | PARODD | PARENB | CSTOPB | CSIZE); + res |= cflag & (CBAUD | PARODD | PARENB | CSTOPB | CSIZE | CLOCAL); return res; } diff -ur --new-file old/linux/drivers/char/pty.c new/linux/drivers/char/pty.c --- old/linux/drivers/char/pty.c Thu Jun 6 20:21:19 1996 +++ new/linux/drivers/char/pty.c Wed Jul 17 14:10:03 1996 @@ -244,6 +244,12 @@ return retval; } +static void pty_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + tty->termios->c_cflag &= ~(CSIZE | PARENB); + tty->termios->c_cflag |= (CS8 | CREAD); +} + int pty_init(void) { memset(&pty_state, 0, sizeof(pty_state)); @@ -274,6 +280,7 @@ pty_driver.flush_buffer = pty_flush_buffer; pty_driver.chars_in_buffer = pty_chars_in_buffer; pty_driver.unthrottle = pty_unthrottle; + pty_driver.set_termios = pty_set_termios; pty_slave_driver = pty_driver; pty_slave_driver.name = "ttyp"; diff -ur --new-file old/linux/drivers/char/random.c new/linux/drivers/char/random.c --- old/linux/drivers/char/random.c Thu Jun 6 21:23:08 1996 +++ new/linux/drivers/char/random.c Tue Jul 2 18:08:42 1996 @@ -357,8 +357,6 @@ #if (!defined (__i386__)) extern inline __u32 rotate_left(int i, __u32 word) { - __u32 nbits = 0; - return (word << i) | (word >> (32 - i)); } diff -ur --new-file old/linux/drivers/char/softdog.c new/linux/drivers/char/softdog.c --- old/linux/drivers/char/softdog.c Mon May 13 06:17:23 1996 +++ new/linux/drivers/char/softdog.c Sat Jun 29 11:00:46 1996 @@ -73,6 +73,7 @@ /* * Activate timer */ + del_timer(&watchdog_ticktock); watchdog_ticktock.expires=jiffies + (soft_margin * HZ); add_timer(&watchdog_ticktock); timer_alive++; diff -ur --new-file old/linux/drivers/char/tty_io.c new/linux/drivers/char/tty_io.c --- old/linux/drivers/char/tty_io.c Thu Jun 6 20:38:57 1996 +++ new/linux/drivers/char/tty_io.c Wed Jul 24 09:53:39 1996 @@ -330,7 +330,7 @@ static int hung_up_tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) { - return -EIO; + return cmd == TIOCSPGRP ? -ENOTTY : -EIO; } static int tty_lseek(struct inode * inode, struct file * file, off_t offset, int orig) @@ -475,8 +475,10 @@ { struct tty_struct *tty = current->tty; struct task_struct *p; + int tty_pgrp = -1; if (tty) { + tty_pgrp = tty->pgrp; if (on_exit && tty->driver.type != TTY_DRIVER_TYPE_PTY) tty_vhangup(tty); } else { @@ -486,9 +488,10 @@ } return; } - if (tty->pgrp > 0) { - kill_pg(tty->pgrp, SIGHUP, on_exit); - kill_pg(tty->pgrp, SIGCONT, on_exit); + if (tty_pgrp > 0) { + kill_pg(tty_pgrp, SIGHUP, on_exit); + if (!on_exit) + kill_pg(tty_pgrp, SIGCONT, on_exit); } current->tty_old_pgrp = 0; @@ -752,9 +755,48 @@ return i; } +/* + * Split writes up in sane blocksizes to avoid + * denial-of-service type attacks + */ +static inline int do_tty_write( + int (*write)(struct tty_struct *, struct file *, const unsigned char *, unsigned int), + struct inode *inode, + struct tty_struct *tty, + struct file *file, + const unsigned char *buf, + unsigned int count) +{ + int ret = 0, written = 0; + + for (;;) { + unsigned int size = PAGE_SIZE*2; + if (size > count) + size = count; + ret = write(tty, file, buf, size); + if (ret <= 0) + break; + count -= ret; + written += ret; + if (!count) + break; + ret = -ERESTARTSYS; + if (current->signal & ~current->blocked) + break; + if (need_resched) + schedule(); + } + if (written) { + inode->i_mtime = CURRENT_TIME; + ret = written; + } + return ret; +} + + static int tty_write(struct inode * inode, struct file * file, const char * buf, int count) { - int i, is_console; + int is_console; struct tty_struct * tty; is_console = (inode->i_rdev == CONSOLE_DEV); @@ -778,14 +820,12 @@ } } #endif - if (tty->ldisc.write) - /* XXX casts are for what kernel-wide prototypes should be. */ - i = (tty->ldisc.write)(tty,file,(const unsigned char *)buf,(unsigned int)count); - else - i = -EIO; - if (i > 0) - inode->i_mtime = CURRENT_TIME; - return i; + if (!tty->ldisc.write) + return -EIO; + return do_tty_write(tty->ldisc.write, + inode, tty, file, + (const unsigned char *)buf, + (unsigned int)count); } /* @@ -1496,6 +1536,8 @@ return 0; case TIOCSPGRP: retval = tty_check_change(real_tty); + if (retval == -EIO) + return -ENOTTY; if (retval) return retval; if (!current->tty || @@ -1816,7 +1858,7 @@ memcpy(tty_std_termios.c_cc, INIT_C_CC, NCCS); tty_std_termios.c_iflag = ICRNL | IXON; tty_std_termios.c_oflag = OPOST | ONLCR; - tty_std_termios.c_cflag = B38400 | CS8 | CREAD; + tty_std_termios.c_cflag = B38400 | CS8 | CREAD | HUPCL; tty_std_termios.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN; diff -ur --new-file old/linux/drivers/isdn/icn/icn.c new/linux/drivers/isdn/icn/icn.c --- old/linux/drivers/isdn/icn/icn.c Fri Jun 7 15:02:40 1996 +++ new/linux/drivers/isdn/icn/icn.c Sat Jun 29 19:36:22 1996 @@ -1,4 +1,4 @@ -/* $Id: icn.c,v 1.24 1996/06/06 13:58:33 fritz Exp $ +/* $Id: icn.c,v 1.28 1996/06/28 17:02:53 fritz Exp $ * * ISDN low-level module for the ICN active ISDN-Card. * @@ -19,6 +19,23 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: icn.c,v $ + * Revision 1.28 1996/06/28 17:02:53 fritz + * replaced memcpy_fromfs_toio. + * + * Revision 1.27 1996/06/25 18:38:59 fritz + * Fixed function name in error message. + * + * Revision 1.26 1996/06/24 17:20:35 fritz + * Bugfixes in pollbchan_send(): + * - Using lock field of skbuff breaks networking. + * - Added channel locking + * - changed dequeuing scheme. + * Eliminated misc. compiler warnings. + * + * Revision 1.25 1996/06/11 22:53:35 tsbogend + * fixed problem with large array on stack + * made the driver working on Linux/alpha + * * Revision 1.24 1996/06/06 13:58:33 fritz * Changed code to be architecture independent * @@ -119,7 +136,7 @@ #undef MAP_DEBUG static char -*revision = "$Revision: 1.24 $"; +*revision = "$Revision: 1.28 $"; static int icn_addcard(int, char *, char *); @@ -135,10 +152,8 @@ save_flags(flags); cli(); - while ((skb = skb_dequeue(queue))) { - skb->free = 1; - kfree_skb(skb, FREE_WRITE); - } + while ((skb = skb_dequeue(queue))) + dev_kfree_skb(skb, FREE_WRITE); restore_flags(flags); } @@ -312,7 +327,7 @@ if (icn_trymaplock_channel(card,mch)) { while (rbavl) { - cnt = rbuf_l; + cnt = readb(&rbuf_l); if ((card->rcvidx[channel] + cnt) > 4000) { printk(KERN_WARNING "icn: (%s) bogus packet on ch%d, dropping.\n", @@ -322,9 +337,9 @@ eflag = 0; } else { memcpy_fromio(&card->rcvbuf[channel][card->rcvidx[channel]], - rbuf_d, cnt); + &rbuf_d, cnt); card->rcvidx[channel] += cnt; - eflag = rbuf_f; + eflag = readb(&rbuf_f); } rbnext; icn_maprelease_channel(card, mch & 2); @@ -367,36 +382,37 @@ while (sbfree && card->sndcount[channel]) { save_flags(flags); cli(); - skb = skb_peek(&card->spqueue[channel]); - if (!skb) { - restore_flags(flags); - break; - } - if (skb->lock) { + if (card->xmit_lock[channel]) { restore_flags(flags); break; } - skb->lock = 1; + card->xmit_lock[channel]++; restore_flags(flags); - cnt = - (sbuf_l = - (skb->len > ICN_FRAGSIZE) ? ((sbuf_f = 0xff), ICN_FRAGSIZE) : ((sbuf_f = 0), skb->len)); - memcpy(sbuf_d, skb->data, cnt); + skb = skb_dequeue(&card->spqueue[channel]); + if (!skb) + break; + if (skb->len > ICN_FRAGSIZE) { + writeb (0xff, &sbuf_f); + cnt = ICN_FRAGSIZE; + } else { + writeb (0x0, &sbuf_f); + cnt = skb->len; + } + writeb (cnt, &sbuf_l); + memcpy_toio(&sbuf_d, skb->data, cnt); skb_pull(skb, cnt); card->sndcount[channel] -= cnt; sbnext; /* switch to next buffer */ icn_maprelease_channel(card, mch & 2); if (!skb->len) { - skb = skb_dequeue(&card->spqueue[channel]); - skb->free = 1; - skb->lock = 0; - kfree_skb(skb, FREE_WRITE); + dev_kfree_skb(skb, FREE_WRITE); cmd.command = ISDN_STAT_BSENT; cmd.driver = card->myid; cmd.arg = channel; card->interface.statcallb(&cmd); } else - skb->lock = 0; + skb_queue_head(&card->spqueue[channel], skb); + card->xmit_lock[channel] = 0; if (!icn_trymaplock_channel(card, mch)) break; } @@ -426,6 +442,7 @@ /* schedule b-channel polling again */ save_flags(flags); cli(); + del_timer(&card->rb_timer); card->rb_timer.expires = jiffies + ICN_TIMER_BCREAD; add_timer(&card->rb_timer); card->flags |= ICN_FLAGS_RBTIMER; @@ -649,6 +666,7 @@ /* schedule again */ save_flags(flags); cli(); + del_timer(&card->st_timer); card->st_timer.expires = jiffies + ICN_TIMER_DCREAD; add_timer(&card->st_timer); restore_flags(flags); @@ -671,8 +689,8 @@ unsigned long flags; if (len > 4000) { - skb->free = 1; - kfree_skb(skb, FREE_WRITE); + printk(KERN_WARNING + "icn: Send packet too large\n"); return -EINVAL; } if (len) { @@ -685,7 +703,6 @@ card->sndcount[channel] += len; skb_queue_tail(&card->spqueue[channel], skb); restore_flags(flags); - icn_pollbchan_send(channel, card); } return len; } @@ -751,13 +768,17 @@ { int ret; ulong flags; - unsigned char codebuf[ICN_CODE_STAGE1]; + u_char *codebuf; #ifdef BOOT_DEBUG printk(KERN_DEBUG "icn_loadboot called, buffaddr=%08lx\n", (ulong) buffer); #endif if ((ret = verify_area(VERIFY_READ, (void *) buffer, ICN_CODE_STAGE1))) return ret; + if (!(codebuf = kmalloc(ICN_CODE_STAGE1,GFP_KERNEL))) { + printk(KERN_WARNING "icn: Could not allocate code buffer\n"); + return -ENOMEM; + } save_flags(flags); cli(); if (!card->rvalid) { @@ -768,6 +789,7 @@ card->port, card->port + ICN_PORTLEN); restore_flags(flags); + kfree(codebuf); return -EBUSY; } request_region(card->port, ICN_PORTLEN, card->regname); @@ -804,8 +826,8 @@ icn_lock_channel(card,0); /* Lock Bank 0 */ restore_flags(flags); SLEEP(1); - memcpy_fromfs(codebuf, buffer, ICN_CODE_STAGE1); /* Copy code */ - memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1); + memcpy_fromfs(codebuf, buffer, ICN_CODE_STAGE1); + memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1); /* Copy code */ #ifdef BOOT_DEBUG printk(KERN_DEBUG "Bootloader transfered\n"); #endif @@ -821,12 +843,12 @@ icn_lock_channel(card,2); /* Lock Bank 8 */ restore_flags(flags); SLEEP(1); - memcpy_fromfs(codebuf, buffer, ICN_CODE_STAGE1); /* Copy code */ - memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1); + memcpy_toio(dev.shmem, codebuf, ICN_CODE_STAGE1); /* Copy code */ #ifdef BOOT_DEBUG printk(KERN_DEBUG "Bootloader transfered\n"); #endif } + kfree(codebuf); SLEEP(1); OUTB_P(0xff, ICN_RUN); /* Start Boot-Code */ if ((ret = icn_check_loader(card->doubleS0 ? 2 : 1))) @@ -849,6 +871,7 @@ static int icn_loadproto(u_char * buffer, icn_card * card) { register u_char *p = buffer; + u_char codebuf[256]; uint left = ICN_CODE_STAGE2; uint cnt; int timer; @@ -874,7 +897,8 @@ while (left) { if (sbfree) { /* If there is a free buffer... */ cnt = MIN(256, left); - memcpy_fromfs(&sbuf_l, p, cnt); /* copy data */ + memcpy_fromfs(codebuf, p, cnt); + memcpy_toio(&sbuf_l, codebuf, cnt); /* copy data */ sbnext; /* switch to next buffer */ p += cnt; left -= cnt; @@ -892,7 +916,7 @@ schedule(); } } - sbuf_n = 0x20; + writeb (0x20, &sbuf_n); timer = 0; while (1) { if (readb(&cmd_o) || readb(&cmd_i)) { @@ -1094,7 +1118,7 @@ } break; case ICN_IOCTL_GETMMIO: - return (int) dev.shmem; + return (long) dev.shmem; case ICN_IOCTL_SETPORT: if (a == 0x300 || a == 0x310 || a == 0x320 || a == 0x330 || a == 0x340 || a == 0x350 || a == 0x360 || @@ -1391,7 +1415,8 @@ if (card) return (icn_command(c, card)); printk(KERN_ERR - "icn: if_command called with invalid driverId!\n"); + "icn: if_command %d called with invalid driverId %d!\n", + c->command, c->driver); return -ENODEV; } @@ -1433,7 +1458,7 @@ return (icn_sendbuf(channel, skb, card)); } printk(KERN_ERR - "icn: if_readstatus called with invalid driverId!\n"); + "icn: if_sendbuf called with invalid driverId!\n"); return -ENODEV; } @@ -1455,9 +1480,6 @@ card->interface.channels = ICN_BCH; card->interface.maxbufsize = 4000; card->interface.command = if_command; - /* - card->interface.writebuf = if_sendbuf; - */ card->interface.writebuf_skb = if_sendbuf; card->interface.writecmd = if_writecmd; card->interface.readstat = if_readstatus; @@ -1558,7 +1580,7 @@ char rev[10]; memset(&dev, 0, sizeof(icn_dev)); - dev.shmem = (icn_shmem *) (membase & 0x0ffc000); + dev.shmem = (icn_shmem *) ((unsigned long)membase & 0x0ffc000); dev.channel = -1; dev.mcard = NULL; @@ -1571,8 +1593,8 @@ *p = 0; } else strcpy(rev, " ??? "); - printk(KERN_NOTICE "ICN-ISDN-driver Rev%smem=0x%08x\n", rev, - (uint) dev.shmem); + printk(KERN_NOTICE "ICN-ISDN-driver Rev%smem=0x%08lx\n", rev, + (ulong) dev.shmem); return (icn_addcard(portbase,icn_id,icn_id2)); } diff -ur --new-file old/linux/drivers/isdn/icn/icn.h new/linux/drivers/isdn/icn/icn.h --- old/linux/drivers/isdn/icn/icn.h Fri Jun 7 15:02:40 1996 +++ new/linux/drivers/isdn/icn/icn.h Sat Jun 29 19:36:22 1996 @@ -1,4 +1,4 @@ -/* $Id: icn.h,v 1.19 1996/06/06 13:58:35 fritz Exp $ +/* $Id: icn.h,v 1.20 1996/06/24 17:20:37 fritz Exp $ * * ISDN lowlevel-module for the ICN active ISDN-Card. * @@ -19,6 +19,13 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: icn.h,v $ + * Revision 1.20 1996/06/24 17:20:37 fritz + * Bugfixes in pollbchan_send(): + * - Using lock field of skbuff breaks networking. + * - Added channel locking + * - changed dequeuing scheme. + * Eliminated misc. compiler warnings. + * * Revision 1.19 1996/06/06 13:58:35 fritz * Changed code to be architecture independent * @@ -155,7 +162,7 @@ #define ICN_CODE_STAGE1 4096 /* Size of bootcode */ #define ICN_CODE_STAGE2 65536 /* Size of protocol-code */ -#define ICN_MAX_SQUEUE 65536 /* Max. outstanding send-data */ +#define ICN_MAX_SQUEUE 8000 /* Max. outstanding send-data (2* hw-buf.) */ #define ICN_FRAGSIZE (250) /* Max. size of send-fragments */ #define ICN_BCH 2 /* Number of supported channels per card */ @@ -240,6 +247,7 @@ struct sk_buff_head spqueue[ICN_BCH]; /* Sendqueue */ char regname[35]; /* Name used for request_region */ + u_char xmit_lock[ICN_BCH]; /* Semaphore for pollbchan_send() */ } icn_card; /* diff -ur --new-file old/linux/drivers/isdn/isdn_common.c new/linux/drivers/isdn/isdn_common.c --- old/linux/drivers/isdn/isdn_common.c Fri Jun 7 15:02:40 1996 +++ new/linux/drivers/isdn/isdn_common.c Sat Jun 29 19:36:22 1996 @@ -1,4 +1,4 @@ -/* $Id: isdn_common.c,v 1.18 1996/06/06 14:51:51 fritz Exp $ +/* $Id: isdn_common.c,v 1.23 1996/06/25 18:35:38 fritz Exp $ * * Linux ISDN subsystem, common used functions (linklevel). * @@ -21,6 +21,25 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_common.c,v $ + * Revision 1.23 1996/06/25 18:35:38 fritz + * Fixed bogus memory access in isdn_set_allcfg(). + * + * Revision 1.22 1996/06/24 17:37:37 fritz + * Bugfix: isdn_timer_ctrl() did restart timer, even if it + * was already running. + * lowlevel driver locking did use wrong parameters. + * + * Revision 1.21 1996/06/15 14:58:20 fritz + * Added version signatures for data structures used + * by userlevel programs. + * + * Revision 1.20 1996/06/12 16:01:49 fritz + * Bugfix: Remote B-channel hangup sometimes did not result + * in a NO CARRIER on tty. + * + * Revision 1.19 1996/06/11 14:52:04 hipp + * minor bugfix in isdn_writebuf_skb_stub() + * * Revision 1.18 1996/06/06 14:51:51 fritz * Changed to support DTMF decoding on audio playback also. * @@ -115,11 +134,12 @@ /* Debugflags */ #undef ISDN_DEBUG_STATCALLB +#define NEW_ISDN_TIMER_CTRL isdn_dev *dev = (isdn_dev *) 0; static int has_exported = 0; -static char *isdn_revision = "$Revision: 1.18 $"; +static char *isdn_revision = "$Revision: 1.23 $"; extern char *isdn_net_revision; extern char *isdn_tty_revision; @@ -222,8 +242,10 @@ save_flags(flags); cli(); - del_timer(&dev->timer); - dev->timer.function = isdn_timer_funct; + del_timer(&dev->timer); +#ifndef NEW_ISDN_TIMER_CTRL + dev->timer.function = isdn_timer_funct; +#endif dev->timer.expires = jiffies + ISDN_TIMER_RES; add_timer(&dev->timer); restore_flags(flags); @@ -245,12 +267,20 @@ dev->tflags |= tf; else dev->tflags &= ~tf; +#ifdef NEW_ISDN_TIMER_CTRL + if (dev->tflags) { + if (!del_timer(&dev->timer)) /* del_timer is 1, when active */ + dev->timer.expires = jiffies + ISDN_TIMER_RES; + add_timer(&dev->timer); + } +#else if (dev->tflags) { - del_timer(&dev->timer); - dev->timer.function = isdn_timer_funct; + del_timer(&dev->timer); + dev->timer.function = isdn_timer_funct; dev->timer.expires = jiffies + ISDN_TIMER_RES; add_timer(&dev->timer); } +#endif restore_flags(flags); } @@ -277,6 +307,7 @@ if (isdn_net_rcv_skb(i, skb)) return; /* No network-device found, deliver to tty or raw-channel */ + skb->free = 1; if (skb->len) { if ((midx = dev->m_idx[i])<0) { /* if midx is invalid, drop packet */ @@ -599,9 +630,9 @@ info = &dev->mdm.info[mi]; if (info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) { - info->msr &= ~(UART_MSR_DCD | UART_MSR_RI); - if (info->online) + if (info->msr & UART_MSR_DCD) isdn_tty_modem_result(3, info); + info->msr &= ~(UART_MSR_DCD | UART_MSR_RI); #ifdef ISDN_DEBUG_MODEM_HUP printk(KERN_DEBUG "Mhup in ISDN_STAT_BHUP\n"); #endif @@ -807,6 +838,8 @@ return (dev->chanmap[minor]); } +#define INF_DV 0x01 /* Data version for /dev/isdninfo */ + static char * isdn_statstr(void) { @@ -1043,7 +1076,8 @@ restore_flags(flags); return ret; } - memcpy_tofs((char *) &i, src, sizeof(int)); + memcpy_fromfs((char *) &i, src, sizeof(int)); + src += sizeof(int); while (i) { char *c; char *c2; @@ -1185,6 +1219,10 @@ if (minor == ISDN_MINOR_STATUS) { switch (cmd) { + case IIOCGETDVR: + return(TTY_DV + + (NET_DV << 8) + + (INF_DV << 16)); case IIOCGETCPS: if (arg) { ulong *p = (ulong *)arg; @@ -1728,7 +1766,7 @@ dev->usage[i] &= ISDN_USAGE_EXCLUSIVE; dev->usage[i] |= usage; isdn_info_update(); - cmd.driver = i; + cmd.driver = d; cmd.arg = 0; cmd.command = ISDN_CMD_LOCK; (void) dev->drv[d]->interface->command(&cmd); @@ -1739,7 +1777,7 @@ dev->usage[i] &= ISDN_USAGE_EXCLUSIVE; dev->usage[i] |= usage; isdn_info_update(); - cmd.driver = i; + cmd.driver = d; cmd.arg = 0; cmd.command = ISDN_CMD_LOCK; (void) dev->drv[d]->interface->command(&cmd); @@ -1878,17 +1916,18 @@ int isdn_writebuf_skb_stub(int drvidx, int chan, struct sk_buff * skb) { int ret; + int len = skb->len; /* skb pointer no longer valid after free */ if (dev->drv[drvidx]->interface->writebuf_skb) ret = dev->drv[drvidx]->interface-> writebuf_skb(drvidx, chan, skb); else { if ((ret = dev->drv[drvidx]->interface-> - writebuf(drvidx,chan,skb->data,skb->len,0)) == skb->len) + writebuf(drvidx,chan,skb->data,skb->len,0)) == len) dev_kfree_skb(skb, FREE_WRITE); } if (ret > 0) - dev->obytes[isdn_dc2minor(drvidx,chan)] += skb->len; + dev->obytes[isdn_dc2minor(drvidx,chan)] += len; return ret; } @@ -2063,6 +2102,10 @@ return -EIO; } memset((char *) dev, 0, sizeof(isdn_dev)); +#ifdef NEW_ISDN_TIMER_CTRL + init_timer(&dev->timer); + dev->timer.function = isdn_timer_funct; +#endif for (i = 0; i < ISDN_MAX_CHANNELS; i++) { dev->drvmap[i] = -1; dev->chanmap[i] = -1; diff -ur --new-file old/linux/drivers/isdn/isdn_net.c new/linux/drivers/isdn/isdn_net.c --- old/linux/drivers/isdn/isdn_net.c Fri Jun 7 15:02:41 1996 +++ new/linux/drivers/isdn/isdn_net.c Wed Jul 17 10:55:48 1996 @@ -1,4 +1,4 @@ -/* $Id: isdn_net.c,v 1.13 1996/06/06 14:25:44 fritz Exp $ +/* $Id: isdn_net.c,v 1.18 1996/07/03 13:48:51 hipp Exp $ * * Linux ISDN subsystem, network interfaces and related functions (linklevel). * @@ -21,6 +21,25 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_net.c,v $ + * Revision 1.18 1996/07/03 13:48:51 hipp + * bugfix: Call dev_purge_queues() only for master device + * + * Revision 1.17 1996/06/25 18:37:37 fritz + * Fixed return count for empty return string in isdn_net_getphones(). + * + * Revision 1.16 1996/06/24 17:48:08 fritz + * Bugfixes: + * - Did not free channel on unbinding. + * - ioctl returned wrong callback settings. + * + * Revision 1.15 1996/06/16 17:42:54 tsbogend + * fixed problem with IP addresses on Linux/Alpha (long is 8 byte there) + * + * Revision 1.14 1996/06/11 14:54:08 hipp + * minor bugfix in isdn_net_send_skb + * changes in BSENT callback handler for syncPPP + * added lp->sav_skb stuff + * * Revision 1.13 1996/06/06 14:25:44 fritz * Changed loglevel of "incoming ... without OAD" message, since * with audio support this is quite normal. @@ -105,7 +124,7 @@ extern void dev_purge_queues(struct device *dev); /* move this to net/core/dev.c */ -char *isdn_net_revision = "$Revision: 1.13 $"; +char *isdn_net_revision = "$Revision: 1.18 $"; /* * Code for raw-networking over ISDN @@ -133,9 +152,9 @@ isdn_net_reset(dev); dev->start = 1; /* Fill in the MAC-level header. */ - for (i = 0; i < ETH_ALEN - sizeof(ulong); i++) + for (i = 0; i < ETH_ALEN - sizeof(u32); i++) dev->dev_addr[i] = 0xfc; - memcpy(&(dev->dev_addr[i]), &dev->pa_addr, sizeof(ulong)); + memcpy(&(dev->dev_addr[i]), &dev->pa_addr, sizeof(u32)); /* If this interface has slaves, start them also */ @@ -182,7 +201,12 @@ dev_kfree_skb(lp->first_skb,FREE_WRITE); lp->first_skb = NULL; } - dev_purge_queues(&lp->netdev->dev); + if(lp->sav_skb) { + dev_kfree_skb(lp->sav_skb,FREE_WRITE); + lp->sav_skb = NULL; + } + if(!lp->master) /* purge only for master device */ + dev_purge_queues(&lp->netdev->dev); lp->dialstate = 0; dev->rx_netdev[isdn_dc2minor(lp->isdn_device,lp->isdn_channel)] = NULL; dev->st_netdev[isdn_dc2minor(lp->isdn_device,lp->isdn_channel)] = NULL; @@ -263,14 +287,19 @@ if ((lp->flags & ISDN_NET_CONNECTED) && (!lp->dialstate)) { lp->stats.tx_packets++; - if(lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && lp->first_skb) { - if(!isdn_net_send_skb(&lp->netdev->dev,lp,lp->first_skb)) { - dev_kfree_skb(lp->first_skb,FREE_WRITE); - lp->first_skb = NULL; + if(lp->p_encap == ISDN_NET_ENCAP_SYNCPPP && lp->sav_skb) { + struct device *mdev; + if(lp->master) + mdev = lp->master; + else + mdev = &lp->netdev->dev; + if(!isdn_net_send_skb(mdev,lp,lp->sav_skb)) { + lp->sav_skb = NULL; mark_bh(NET_BH); } - else + else { return 1; + } } if (clear_bit(0,(void*)&(p->dev.tbusy))) mark_bh(NET_BH); @@ -293,8 +322,14 @@ /* Either D-Channel-hangup or error during dialout */ if ((!lp->dialstate) && (lp->flags & ISDN_NET_CONNECTED)) { lp->flags &= ~ISDN_NET_CONNECTED; - if(lp->first_skb) + if(lp->first_skb) { dev_kfree_skb(lp->first_skb,FREE_WRITE); + lp->first_skb = NULL; + } + if(lp->sav_skb) { + dev_kfree_skb(lp->sav_skb,FREE_WRITE); + lp->sav_skb = NULL; + } isdn_free_channel(lp->isdn_device, lp->isdn_channel, ISDN_USAGE_NET); #ifdef CONFIG_ISDN_PPP @@ -596,35 +631,20 @@ { isdn_net_local *lp = (isdn_net_local *) d->priv; isdn_ctrl cmd; - ulong flags; - save_flags(flags); - cli(); - if (lp->first_skb) { - dev_kfree_skb(lp->first_skb,FREE_WRITE); - lp->first_skb = NULL; - } - dev_purge_queues(d); if (lp->flags & ISDN_NET_CONNECTED) { printk(KERN_INFO "isdn_net: local hangup %s\n", lp->name); - lp->dialstate = 0; - dev->rx_netdev[isdn_dc2minor(lp->isdn_device,lp->isdn_channel)] = NULL; - dev->st_netdev[isdn_dc2minor(lp->isdn_device,lp->isdn_channel)] = NULL; - isdn_free_channel(lp->isdn_device, lp->isdn_channel, ISDN_USAGE_NET); #ifdef CONFIG_ISDN_PPP isdn_ppp_free(lp); #endif - lp->flags &= ~ISDN_NET_CONNECTED; cmd.driver = lp->isdn_device; cmd.command = ISDN_CMD_HANGUP; cmd.arg = lp->isdn_channel; (void) dev->drv[cmd.driver]->interface->command(&cmd); printk(KERN_INFO "%s: Chargesum is %d\n", lp->name, lp->charge); isdn_all_eaz(lp->isdn_device, lp->isdn_channel); - lp->isdn_device = -1; - lp->isdn_channel = -1; } - restore_flags(flags); + isdn_net_unbind_channel(lp); } typedef struct { @@ -732,13 +752,21 @@ struct sk_buff *skb) { int ret; + int len = skb->len; /* save len */ - lp->transcount += skb->len; ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, skb); - if (ret == skb->len) { + if (ret == len) { + lp->transcount += len; clear_bit(0, (void *)&(ndev->tbusy)); return 0; } + if (ret < 0) { + skb->free = 1; + dev_kfree_skb(skb, FREE_WRITE); + lp->stats.tx_errors++; + clear_bit(0, (void *)&(ndev->tbusy)); + return 0; + } return 1; } @@ -762,8 +790,7 @@ /* For the other encaps the header has already been built */ #ifdef CONFIG_ISDN_PPP if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) { - ndev->tbusy = ret = isdn_ppp_xmit(skb, ndev); - return ret; + return isdn_ppp_xmit(skb, ndev); } #endif /* Reset hangup-timeout */ @@ -877,7 +904,7 @@ if (lp->p_encap == ISDN_NET_ENCAP_SYNCPPP) { /* no 'first_skb' handling for syncPPP */ if (isdn_ppp_bind(lp) < 0) { - lp->first_skb = skb; /* net_unbind will free skb */ + dev_kfree_skb(skb,FREE_WRITE); isdn_net_unbind_channel(lp); restore_flags(flags); return 0; /* STN (skb to nirvana) ;) */ @@ -1241,7 +1268,7 @@ * guaranteed to be invalid. Need that to check * for already compressed packets in isdn_ppp_xmit(). */ - *((unsigned long *)skb_push(skb, len)) = 0; + *((u32 *)skb_push(skb, len)) = 0; break; #endif } @@ -1251,7 +1278,7 @@ /* We don't need to send arp, because we have point-to-point connections. */ static int -isdn_net_rebuild_header(void *buff, struct device *dev, ulong dst, +isdn_net_rebuild_header(void *buff, struct device *dev, unsigned long dst, struct sk_buff *skb) { isdn_net_local *lp = dev->priv; @@ -1266,8 +1293,8 @@ if(eth->h_proto != htons(ETH_P_IP)) { printk(KERN_WARNING - "isdn_net_rebuild_header: Don't know how to resolve type %d addresses?\n", - (int)eth->h_proto); + "isdn_net: %s don't know how to resolve type %d addresses?\n", + dev->name, (int)eth->h_proto); memcpy(eth->h_source, dev->dev_addr, dev->addr_len); return 0; } @@ -1275,7 +1302,7 @@ * Try to get ARP to resolve the header. */ #ifdef CONFIG_INET - ret = arp_find((unsigned char *)&(eth->h_dest), dst, dev, dev->pa_addr,skb)? 1 : 0; + ret = arp_find(eth->h_dest, dst, dev, dev->pa_addr, skb)? 1 : 0; #endif } return ret; @@ -2034,6 +2061,7 @@ p->local.exclusive = -1; if ((p->local.pre_device != -1) && (cfg->exclusive == -1)) { isdn_unexclusive_channel(p->local.pre_device, p->local.pre_channel); + isdn_free_channel(p->local.pre_device, p->local.pre_channel,ISDN_USAGE_NET); drvidx = -1; chidx = -1; } @@ -2059,7 +2087,7 @@ p->local.flags &= ~ISDN_NET_CBHUP; switch (cfg->callback) { case 0: - p->local.flags &= ~(ISDN_NET_CALLBACK&ISDN_NET_CBOUT); + p->local.flags &= ~(ISDN_NET_CALLBACK|ISDN_NET_CBOUT); break; case 1: p->local.flags |= ISDN_NET_CALLBACK; @@ -2126,7 +2154,9 @@ cfg->secure = (p->local.flags & ISDN_NET_SECURE) ? 1 : 0; cfg->callback = 0; if (p->local.flags & ISDN_NET_CALLBACK) - cfg->callback = (p->local.flags & ISDN_NET_CBOUT)?2:1; + cfg->callback = 1; + if (p->local.flags & ISDN_NET_CBOUT) + cfg->callback = 2; cfg->cbhup = (p->local.flags & ISDN_NET_CBHUP) ? 1 : 0; cfg->chargehup = (p->local.hupflags & 4) ? 1 : 0; cfg->ihup = (p->local.hupflags & 8) ? 1 : 0; @@ -2186,10 +2216,7 @@ save_flags(flags); cli(); inout &= 1; - n = p->local.phone[inout]; - if (n) - count++; - while (n) { + for (n = p->local.phone[inout]; n; n = n->next) { if (more) { put_fs_byte(' ', phones++); count++; @@ -2201,10 +2228,10 @@ memcpy_tofs(phones, n->num, strlen(n->num) + 1); phones += strlen(n->num); count += strlen(n->num); - n = n->next; more = 1; } put_fs_byte(0,phones); + count++; restore_flags(flags); return count; } diff -ur --new-file old/linux/drivers/isdn/isdn_ppp.c new/linux/drivers/isdn/isdn_ppp.c --- old/linux/drivers/isdn/isdn_ppp.c Sun May 19 14:29:29 1996 +++ new/linux/drivers/isdn/isdn_ppp.c Wed Jul 17 10:55:48 1996 @@ -1,4 +1,4 @@ -/* $Id: isdn_ppp.c,v 1.9 1996/05/18 01:37:01 fritz Exp $ +/* $Id: isdn_ppp.c,v 1.13 1996/07/01 19:47:24 hipp Exp $ * * Linux ISDN subsystem, functions for synchronous PPP (linklevel). * @@ -19,6 +19,19 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_ppp.c,v $ + * Revision 1.13 1996/07/01 19:47:24 hipp + * Fixed memory leak in VJ handling and more VJ changes + * + * Revision 1.12 1996/06/24 17:42:03 fritz + * Minor bugfixes. + * + * Revision 1.11 1996/06/16 17:46:05 tsbogend + * changed unsigned long to u32 to make Alpha people happy + * + * Revision 1.10 1996/06/11 14:50:29 hipp + * Lot of changes and bugfixes. + * New scheme to resend packets to busy LL devices. + * * Revision 1.9 1996/05/18 01:37:01 fritz * Added spelling corrections and some minor changes * to stay in sync with kernel. @@ -69,7 +82,7 @@ #endif /* Prototypes */ -static int isdn_ppp_fill_rq(char *buf, int len,int proto, int minor); +static int isdn_ppp_fill_rq(unsigned char *buf, int len,int proto, int minor); static int isdn_ppp_closewait(int); static void isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff *skb, int proto); @@ -83,7 +96,7 @@ int BEbyte, int *sqno, int min_sqno); #endif -char *isdn_ppp_revision = "$Revision: 1.9 $"; +char *isdn_ppp_revision = "$Revision: 1.13 $"; struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS]; extern int isdn_net_force_dial_lp(isdn_net_local *); @@ -95,10 +108,13 @@ int isdn_ppp_free(isdn_net_local *lp) { isdn_net_local *master_lp=lp; + unsigned long flags; if (lp->ppp_minor < 0) return 0; + save_flags(flags); + cli(); #ifdef CONFIG_ISDN_MPP if(lp->master) master_lp = (isdn_net_local *) lp->master->priv; @@ -123,6 +139,7 @@ ippp_table[lp->ppp_minor]->lp = NULL; /* link is down .. set lp to NULL */ lp->ppp_minor = -1; /* is this OK ?? */ + restore_flags(flags); return 0; } @@ -241,12 +258,6 @@ /* * VJ header compression init */ - ippp_table[minor]->cbuf = kmalloc(ippp_table[minor]->mru + PPP_HARD_HDR_LEN + 2, GFP_KERNEL); - - if (ippp_table[minor]->cbuf == NULL) { - printk(KERN_DEBUG "ippp: Can't allocate memory buffer for VJ compression.\n"); - return -ENOMEM; - } ippp_table[minor]->slcomp = slhc_init(16, 16); /* not necessary for 2. link in bundle */ #endif @@ -286,7 +297,7 @@ #ifdef CONFIG_ISDN_PPP_VJ slhc_free(ippp_table[minor]->slcomp); - kfree(ippp_table[minor]->cbuf); + ippp_table[minor]->slcomp = NULL; #endif ippp_table[minor]->state = 0; @@ -394,7 +405,25 @@ case PPPIOCSMAXCID: /* set the maximum compression slot id */ if ((r = get_arg((void *) arg, &val))) return r; - ippp_table[minor]->maxcid = val; + val++; + if(ippp_table[minor]->maxcid != val) { +#ifdef CONFIG_ISDN_PPP_VJ + struct slcompress *sltmp; +#endif + if(ippp_table[minor]->debug & 0x1) + printk(KERN_DEBUG "ippp, ioctl: changed MAXCID to %ld\n",val); + ippp_table[minor]->maxcid = val; +#ifdef CONFIG_ISDN_PPP_VJ + sltmp = slhc_init(16,val); + if(!sltmp) { + printk(KERN_ERR "ippp, can't realloc slhc struct\n"); + return -ENOMEM; + } + if(ippp_table[minor]->slcomp) + slhc_free(ippp_table[minor]->slcomp); + ippp_table[minor]->slcomp = sltmp; +#endif + } break; case PPPIOCGDEBUG: if ((r = set_arg((void *) arg, ippp_table[minor]->debug))) @@ -453,10 +482,11 @@ * fill up isdn_ppp_read() queue .. */ -static int isdn_ppp_fill_rq(char *buf, int len,int proto, int minor) +static int isdn_ppp_fill_rq(unsigned char *buf, int len,int proto, int minor) { struct ippp_buf_queue *bf, *bl; unsigned long flags; + unsigned char *nbuf; if (minor < 0 || minor >= ISDN_MAX_CHANNELS) { printk(KERN_WARNING "ippp: illegal minor.\n"); @@ -466,6 +496,18 @@ printk(KERN_DEBUG "ippp: device not activated.\n"); return 0; } + + nbuf = (unsigned char *) kmalloc(len+4, GFP_ATOMIC); + if(!nbuf) { + printk(KERN_WARNING "ippp: Can't alloc buf\n"); + return 0; + } + nbuf[0] = PPP_ALLSTATIONS; + nbuf[1] = PPP_UI; + nbuf[2] = proto >> 8; + nbuf[3] = proto & 0xff; + memcpy(nbuf+4, buf, len); + save_flags(flags); cli(); @@ -478,20 +520,9 @@ kfree(bf->buf); ippp_table[minor]->first = bf; } - bl->buf = (char *) kmalloc(len+4, GFP_ATOMIC); - if (!bl->buf) { - printk(KERN_WARNING "ippp: Can't alloc buf\n"); - restore_flags(flags); - return 0; - } + bl->buf = (char *) nbuf; bl->len = len+4; - bl->buf[0] = PPP_ALLSTATIONS; - bl->buf[1] = PPP_UI; - bl->buf[2] = proto >> 8; - bl->buf[3] = proto & 0xff; - memcpy(bl->buf+4, buf, len); - ippp_table[minor]->last = bl->next; restore_flags(flags); @@ -561,9 +592,23 @@ return 0; if (dev->drv[lp->isdn_device]->running && lp->dialstate == 0 && - (lp->flags & ISDN_NET_CONNECTED)) - isdn_writebuf_stub(lp->isdn_device,lp->isdn_channel, - buf, count, 1); + (lp->flags & ISDN_NET_CONNECTED)) { + struct sk_buff *skb; + skb = dev_alloc_skb(count); + if(!skb) { + printk(KERN_WARNING "isdn_ppp_write: out of memory!\n"); + return count; + } + skb->free = 1; + memcpy_fromfs(skb_put(skb, count), buf, count); + if(isdn_writebuf_skb_stub(lp->isdn_device,lp->isdn_channel,skb) != count) { + if(lp->sav_skb) { + dev_kfree_skb(lp->sav_skb,FREE_WRITE); + printk(KERN_INFO "isdn_ppp_write: freeing sav_skb!\n"); + } + lp->sav_skb = skb; + } + } } return count; @@ -617,10 +662,16 @@ if(ippp_table[lp->ppp_minor]->debug & 0x4) printk(KERN_DEBUG "recv skb, len: %ld\n",skb->len); + if(net_dev->local.master) { + printk(KERN_WARNING "isdn_ppp_receice: net_dev != master\n"); + net_dev = ((isdn_net_local*) net_dev->local.master->priv)->netdev; + } + if(skb->data[0] == 0xff && skb->data[1] == 0x03) skb_pull(skb,2); else if (ippp_table[lp->ppp_minor]->pppcfg & SC_REJ_COMP_AC) { - dev_kfree_skb(skb,FREE_WRITE); + skb->free = 1; + dev_kfree_skb(skb,0 /* FREE_READ */ ); return; /* discard it silently */ } @@ -714,7 +765,8 @@ if (!q) { net_dev->ib.modify = 0; printk(KERN_WARNING "ippp/MPPP: Bad! Can't alloc sq node!\n"); - dev_kfree_skb(skb,FREE_WRITE); + skb->free = 1; + dev_kfree_skb(skb, 0 /* FREE_READ */ ); return; /* discard */ } q->skb = skb; @@ -787,30 +839,46 @@ switch (proto) { case PPP_IPX: /* untested */ + if(ippp_table[lp->ppp_minor]->debug & 0x20) + printk(KERN_DEBUG "isdn_ppp: _IPX\n"); skb->dev = dev; skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IPX); break; #ifdef CONFIG_ISDN_PPP_VJ case PPP_VJC_UNCOMP: - slhc_remember(ippp_table[net_dev->local.ppp_minor]->slcomp, skb->data, skb->len); + if(ippp_table[lp->ppp_minor]->debug & 0x20) + printk(KERN_DEBUG "isdn_ppp: VJC_UNCOMP\n"); + if(slhc_remember(ippp_table[net_dev->local.ppp_minor]->slcomp, skb->data, skb->len) <= 0) { + printk(KERN_WARNING "isdn_ppp: received illegal VJC_UNCOMP frame!\n"); + net_dev->local.stats.rx_dropped++; + skb->free = 1; + dev_kfree_skb(skb,0 /* FREE_READ */ ); + return; + } #endif case PPP_IP: + if(ippp_table[lp->ppp_minor]->debug & 0x20) + printk(KERN_DEBUG "isdn_ppp: IP\n"); skb->dev = dev; skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IP); break; case PPP_VJC_COMP: + if(ippp_table[lp->ppp_minor]->debug & 0x20) + printk(KERN_DEBUG "isdn_ppp: VJC_COMP\n"); #ifdef CONFIG_ISDN_PPP_VJ { struct sk_buff *skb_old = skb; int pkt_len; skb = dev_alloc_skb(skb_old->len + 40); + skb_old->free = 1; + if (!skb) { printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); net_dev->local.stats.rx_dropped++; - dev_kfree_skb(skb_old,FREE_WRITE); + dev_kfree_skb(skb_old,0 /* FREE_READ */ ); return; } skb->dev = dev; @@ -819,20 +887,28 @@ skb->mac.raw = skb->data; pkt_len = slhc_uncompress(ippp_table[net_dev->local.ppp_minor]->slcomp, skb->data, skb_old->len); + dev_kfree_skb(skb_old,0 /* FREE_READ */ ); + if(pkt_len < 0) { + skb->free = 1; + dev_kfree_skb(skb, 0 /* FREE_READ */ ); + lp->stats.rx_dropped++; + return; + } skb_trim(skb, pkt_len); - dev_kfree_skb(skb_old,FREE_WRITE); skb->protocol = htons(ETH_P_IP); } #else printk(KERN_INFO "isdn: Ooopsa .. VJ-Compression support not compiled into isdn driver.\n"); lp->stats.rx_dropped++; - dev_kfree_skb(skb,FREE_WRITE); + skb->free = 1; + dev_kfree_skb(skb,0 /* FREE_READ */ ); return; #endif break; default: isdn_ppp_fill_rq(skb->data, skb->len,proto, lp->ppp_minor); /* push data to pppd device */ - dev_kfree_skb(skb,FREE_WRITE); + skb->free = 1; + dev_kfree_skb(skb,0 /* FREE_READ */ ); return; } @@ -847,7 +923,11 @@ /* * send ppp frame .. we expect a PIDCOMPressable proto -- * (here: currently always PPP_IP,PPP_VJC_COMP,PPP_VJC_UNCOMP) + * + * VJ compression may change skb pointer!!! .. requeue with old + * skb isn't allowed!! */ + int isdn_ppp_xmit(struct sk_buff *skb, struct device *dev) { struct device *mdev = ((isdn_net_local *) (dev->priv) )->master; /* get master (for redundancy) */ @@ -861,34 +941,44 @@ else mlp = (isdn_net_local *) (dev->priv); nd = mlp->netdev; /* get master lp */ - lp = nd->queue; /* get lp on top of queue */ - ipt = ippp_table[lp->ppp_minor]; ipts = ippp_table[mlp->ppp_minor]; - if (!(ipt->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */ - printk(KERN_INFO "isdn, xmit: Packet blocked: %d %d\n", lp->isdn_device, lp->isdn_channel); + if (!(ipts->pppcfg & SC_ENABLE_IP)) { /* PPP connected ? */ + printk(KERN_INFO "%s: IP frame delayed.\n",dev->name); return 1; } + + lp = nd->queue; /* get lp on top of queue */ + if(lp->sav_skb) { /* find a non-busy device */ + isdn_net_local *nlp = lp->next; + while(lp->sav_skb) { + if(lp == nlp) + return 1; + nlp = nd->queue = nd->queue->next; + } + lp = nlp; + } + ipt = ippp_table[lp->ppp_minor]; + lp->huptimer = 0; /* If packet is to be resent, it has already been processed and * therefore its first bytes are already initialized. In this case * send it immediately ... */ - if (*((unsigned long *)skb->data) != 0) + if (*((u32 *)skb->data) != 0) { + printk(KERN_ERR "%s: Whoops .. packet resend should no longer happen!\n",dev->name); return (isdn_net_send_skb(dev , lp , skb)); + } /* ... else packet needs processing. */ -/* future: step to next 'lp' when this lp is 'tbusy' */ - if(ippp_table[lp->ppp_minor]->debug & 0x4) printk(KERN_DEBUG "xmit skb, len %ld\n",skb->len); #ifdef CONFIG_ISDN_PPP_VJ - if (ipt->pppcfg & SC_COMP_TCP) { /* ipt or ipts ? -> check this again! */ - u_char *buf = skb->data; - int pktlen; + if (ipts->pppcfg & SC_COMP_TCP) { /* ipts here? probably yes .. but check again */ + struct sk_buff *new_skb; int len = 4; #ifdef CONFIG_ISDN_MPP if (ipt->mpppcfg & SC_MP_PROT) /* sigh */ /* ipt or ipts ?? */ @@ -897,20 +987,41 @@ else len += 5; #endif - buf += len; - pktlen = slhc_compress(ipts->slcomp, buf, skb->len-len, ipts->cbuf, - &buf, !(ipts->pppcfg & SC_NO_TCP_CCID)); - skb_trim(skb,pktlen+len); - if(buf != skb->data+len) { /* copied to new buffer ??? (btw: WHY must slhc copy it?? *sigh*) */ - memcpy(skb->data+len,buf,pktlen); - } - if (skb->data[len] & SL_TYPE_COMPRESSED_TCP) { /* cslip? style -> PPP */ - proto = PPP_VJC_COMP; - skb->data[len] ^= SL_TYPE_COMPRESSED_TCP; - } else { - if (skb->data[len] >= SL_TYPE_UNCOMPRESSED_TCP) - proto = PPP_VJC_UNCOMP; - skb->data[len] = (skb->data[len] & 0x0f) | 0x40; + new_skb = dev_alloc_skb(skb->len); + if(new_skb) { + u_char *buf; + int pktlen; + + new_skb->dev = skb->dev; + new_skb->free = 1; + skb_put(new_skb,skb->len); + skb_pull(skb,len); /* pull PPP header */ + skb_pull(new_skb,len); /* pull PPP header */ + buf = skb->data; + + pktlen = slhc_compress(ipts->slcomp, skb->data, skb->len, new_skb->data, + &buf, !(ipts->pppcfg & SC_NO_TCP_CCID)); + + if(buf != skb->data) { /* copied to new buffer ??? (btw: WHY must slhc copy it?? *sigh*) */ + if(new_skb->data != buf) + printk(KERN_ERR "isdn_ppp: FATAL error after slhc_compress!!\n"); + dev_kfree_skb(skb,FREE_WRITE); + skb = new_skb; + } + else { + dev_kfree_skb(new_skb,0 /* FREE_WRITE */ ); + } + + skb_trim(skb,pktlen); + if (skb->data[0] & SL_TYPE_COMPRESSED_TCP) { /* cslip? style -> PPP */ + proto = PPP_VJC_COMP; + skb->data[0] ^= SL_TYPE_COMPRESSED_TCP; + } else { + if (skb->data[0] >= SL_TYPE_UNCOMPRESSED_TCP) + proto = PPP_VJC_UNCOMP; + skb->data[0] = (skb->data[0] & 0x0f) | 0x40; + } + skb_push(skb,len); } } #endif @@ -947,7 +1058,15 @@ skb->data[3] = proto & 0xff; /* tx-stats are now updated via BSENT-callback */ - return (isdn_net_send_skb(dev , lp , skb)); + if(isdn_net_send_skb(dev , lp , skb)) { + if(lp->sav_skb) { /* whole sav_skb processing with disabled IRQs ?? */ + printk(KERN_ERR "%s: whoops .. there is another stored skb!\n",dev->name); + dev_kfree_skb(skb,FREE_WRITE); + } + else + lp->sav_skb = skb; + } + return 0; } void isdn_ppp_free_sqqueue(isdn_net_dev * p) @@ -957,8 +1076,10 @@ p->ib.sq = NULL; while(q) { struct sqqueue *qn = q->next; - if(q->skb) - dev_kfree_skb(q->skb,FREE_WRITE); + if(q->skb) { + q->skb->free = 1; + dev_kfree_skb(q->skb,0 /* FREE_READ */ ); + } kfree(q); q = qn; } @@ -970,7 +1091,8 @@ struct mpqueue *ql, *q = p->mp_last; while (q) { ql = q->next; - dev_kfree_skb(q->skb,FREE_WRITE); + q->skb->free = 1; + dev_kfree_skb(q->skb,0 /* FREE_READ */ ); kfree(q); q = ql; } @@ -1139,7 +1261,8 @@ if (!(*skb)) { while (q) { struct mpqueue *ql = q->next; - dev_kfree_skb(q->skb,FREE_WRITE); + q->skb->free = 1; + dev_kfree_skb(q->skb,0 /* FREE_READ */ ); kfree(q); q = ql; } @@ -1151,7 +1274,8 @@ struct mpqueue *ql = q->next; memcpy((*skb)->data + cnt, q->skb->data, q->skb->len); cnt += q->skb->len; - dev_kfree_skb(q->skb,FREE_WRITE); + q->skb->free = 1; + dev_kfree_skb(q->skb,0 /* FREE_READ */ ); kfree(q); q = ql; } @@ -1165,6 +1289,9 @@ static void isdn_ppp_cleanup_queue(isdn_net_dev * dev, long min_sqno) { +#ifdef CONFIG_ISDN_PPP_VJ + int toss = 0; +#endif /* z.z einfaches aussortieren gammeliger pakete. Fuer die Zukunft: eventuell, solange vorne kein B-paket ist und sqno<=min_sqno: auch rauswerfen wenn sqnonext->last = NULL; while (q) { ql = q->last; - dev_kfree_skb(q->skb,FREE_WRITE); + q->skb->free = 1; + dev_kfree_skb(q->skb,0 /* FREE_READ */ ); kfree(q); +#ifdef CONFIG_ISDN_PPP_VJ + toss = 1; +#endif q = ql; } q = dev->mp_last; @@ -1191,6 +1322,11 @@ } else break; } +#ifdef CONFIG_ISDN_PPP_VJ + /* did we free a stale frame ? */ + if(toss) + slhc_toss(ippp_table[dev->local.ppp_minor]->slcomp); +#endif } /* @@ -1207,7 +1343,7 @@ while (net_dev) { isdn_net_local *lp = &net_dev->local; - if (net_dev->ib.modify) { /* interface locked? */ + if (net_dev->ib.modify || lp->master) { /* interface locked or slave?*/ net_dev = net_dev->next; continue; } @@ -1215,6 +1351,13 @@ q = net_dev->ib.sq; while (q) { if (q->sqno_start == net_dev->ib.next_num || q->timer < jiffies) { + +#ifdef CONFIG_ISDN_PPP_VJ + /* did we step over a missing frame ? */ + if(q->sqno_start != net_dev->ib.next_num) + slhc_toss(ippp_table[lp->ppp_minor]->slcomp); +#endif + ql = net_dev->ib.sq; net_dev->ib.sq = q->next; net_dev->ib.next_num = q->sqno_end + 1; @@ -1234,6 +1377,49 @@ #endif } +/* + * network device ioctl handlers + */ + +static int isdn_ppp_dev_ioctl_stats(int minor,struct ifreq *ifr,struct device *dev) +{ + struct ppp_stats *res, t; + isdn_net_local *lp = (isdn_net_local *) dev->priv; + int err; + + res = (struct ppp_stats *) ifr->ifr_ifru.ifru_data; + err = verify_area (VERIFY_WRITE, res,sizeof(struct ppp_stats)); + + if(err) + return err; + + /* build a temporary stat struct and copy it to user space */ + + memset (&t, 0, sizeof(struct ppp_stats)); + if(dev->flags & IFF_UP) { + t.p.ppp_ipackets = lp->stats.rx_packets; + t.p.ppp_ierrors = lp->stats.rx_errors; + t.p.ppp_opackets = lp->stats.tx_packets; + t.p.ppp_oerrors = lp->stats.tx_errors; +#ifdef CONFIG_ISDN_PPP_VJ + if(minor >= 0 && ippp_table[minor]->slcomp) { + struct slcompress *slcomp = ippp_table[minor]->slcomp; + t.vj.vjs_packets = slcomp->sls_o_compressed+slcomp->sls_o_uncompressed; + t.vj.vjs_compressed = slcomp->sls_o_compressed; + t.vj.vjs_searches = slcomp->sls_o_searches; + t.vj.vjs_misses = slcomp->sls_o_misses; + t.vj.vjs_errorin = slcomp->sls_i_error; + t.vj.vjs_tossed = slcomp->sls_i_tossed; + t.vj.vjs_uncompressedin = slcomp->sls_i_uncompressed; + t.vj.vjs_compressedin = slcomp->sls_i_compressed; + } +#endif + } + memcpy_tofs (res, &t, sizeof (struct ppp_stats)); + return 0; + +} + int isdn_ppp_dev_ioctl(struct device *dev, struct ifreq *ifr, int cmd) { int error; @@ -1241,19 +1427,27 @@ int len; isdn_net_local *lp = (isdn_net_local *) dev->priv; +#if 0 + printk(KERN_DEBUG "ippp, dev_ioctl: cmd %#08x , %d \n",cmd,lp->ppp_minor); +#endif + if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) return -EINVAL; switch (cmd) { - case SIOCGPPPVER: - r = (char *) ifr->ifr_ifru.ifru_data; - len = strlen(PPP_VERSION) + 1; - error = verify_area(VERIFY_WRITE, r, len); - if (!error) - memcpy_tofs(r, PPP_VERSION, len); - break; - default: - error = -EINVAL; + case SIOCGPPPVER: + r = (char *) ifr->ifr_ifru.ifru_data; + len = strlen(PPP_VERSION) + 1; + error = verify_area(VERIFY_WRITE, r, len); + if (!error) + memcpy_tofs(r, PPP_VERSION, len); + break; + case SIOCGPPPSTATS: + error = isdn_ppp_dev_ioctl_stats (lp->ppp_minor, ifr, dev); + break; + default: + error = -EINVAL; + break; } return error; } diff -ur --new-file old/linux/drivers/isdn/isdn_tty.c new/linux/drivers/isdn/isdn_tty.c --- old/linux/drivers/isdn/isdn_tty.c Fri Jun 7 15:02:41 1996 +++ new/linux/drivers/isdn/isdn_tty.c Sat Jun 29 19:36:22 1996 @@ -1,4 +1,4 @@ -/* $Id: isdn_tty.c,v 1.18 1996/06/07 11:17:33 tsbogend Exp $ +/* $Id: isdn_tty.c,v 1.21 1996/06/24 17:40:28 fritz Exp $ * * Linux ISDN subsystem, tty functions and AT-command emulator (linklevel). * @@ -20,6 +20,18 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_tty.c,v $ + * Revision 1.21 1996/06/24 17:40:28 fritz + * Bugfix: Did not compile without CONFIG_ISDN_AUDIO + * + * Revision 1.20 1996/06/15 14:59:39 fritz + * Fixed isdn_tty_tint() to handle partially sent + * sk_buffs. + * + * Revision 1.19 1996/06/12 15:53:56 fritz + * Bugfix: AT+VTX and AT+VRX could be executed without + * having a connection. + * Missing check for NULL tty in isdn_tty_flush_buffer(). + * * Revision 1.18 1996/06/07 11:17:33 tsbogend * added missing #ifdef CONFIG_ISDN_AUDIO to make compiling without * audio support possible @@ -127,7 +139,7 @@ static int bit2si[8] = {1,5,7,7,7,7,7,7}; static int si2bit[8] = {4,1,4,4,4,4,4,4}; -char *isdn_tty_revision = "$Revision: 1.18 $"; +char *isdn_tty_revision = "$Revision: 1.21 $"; #define DLE 0x10 #define ETX 0x03 @@ -262,10 +274,13 @@ static void isdn_tty_tint(modem_info *info) { struct sk_buff *skb = skb_dequeue(&info->xmit_queue); + int len, slen; if (!skb) return; - if (isdn_writebuf_skb_stub(info->isdn_driver, info->isdn_channel, skb) > 0) { + len = skb->len; + if ((slen = isdn_writebuf_skb_stub(info->isdn_driver, + info->isdn_channel, skb)) == len) { struct tty_struct *tty = info->tty; info->send_outstanding++; info->msr |= UART_MSR_CTS; @@ -276,6 +291,8 @@ wake_up_interruptible(&tty->write_wait); return; } + if (slen > 0) + skb_pull(skb,slen); skb_queue_head(&info->xmit_queue, skb); } @@ -369,10 +386,11 @@ } return 0; } -#endif /* CONFIG_ISDN_AUDIO */ static int voice_cf[7] = { 1, 1, 4, 3, 2, 1, 1 }; +#endif /* CONFIG_ISDN_AUDIO */ + /* isdn_tty_senddown() is called either directly from within isdn_tty_write() * or via timer-interrupt from within isdn_tty_modem_xmit(). It pulls * outgoing data from the tty's xmit-buffer, handles voice-decompression or @@ -398,8 +416,8 @@ return; } skb_res = dev->drv[info->isdn_driver]->interface->hl_hdrlen + 4; - if (info->vonline & 2) { #ifdef CONFIG_ISDN_AUDIO + if (info->vonline & 2) { /* For now, ifmt is fixed to 1 (alaw), since this * is used with ISDN everywhere in the world, except * US, Canada and Japan. @@ -454,8 +472,8 @@ if (!info->vonline) isdn_tty_at_cout("\r\nVCON\r\n",info); } -#endif /* CONFIG_ISDN_AUDIO */ } else { +#endif /* CONFIG_ISDN_AUDIO */ skb = dev_alloc_skb(buflen + skb_res); if (!skb) { printk(KERN_WARNING @@ -467,7 +485,9 @@ memcpy(skb_put(skb,buflen),buf,buflen); info->xmit_count = 0; restore_flags(flags); +#ifdef CONFIG_ISDN_AUDIO } +#endif skb->free = 1; if (info->emu.mdmreg[13] & 2) /* Add T.70 simplified header */ @@ -591,6 +611,9 @@ if (!info) return; +#ifdef ISDN_DEBUG_MODEM_HUP + printk(KERN_DEBUG "Mhup ttyI%d\n", info->line); +#endif info->rcvsched = 0; info->online = 0; isdn_tty_flush_buffer(info->tty); @@ -896,13 +919,20 @@ static void isdn_tty_flush_buffer(struct tty_struct *tty) { - modem_info *info = (modem_info *) tty->driver_data; + modem_info *info; unsigned long flags; - if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_flush_buffer")) - return; save_flags(flags); cli(); + if (!tty) { + restore_flags(flags); + return; + } + info = (modem_info *) tty->driver_data; + if (isdn_tty_paranoia_check(info, tty->device, "isdn_tty_flush_buffer")) { + restore_flags(flags); + return; + } isdn_tty_cleanup_xmit(info); info->xmit_count = 0; restore_flags(flags); @@ -2324,6 +2354,10 @@ /* AT+VRX - Start recording */ if (!m->vpar[0]) PARSE_ERROR1; + if (info->online != 1) { + isdn_tty_modem_result(8, info); + return 1; + } info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state); if (!info->dtmf_state) { printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n"); @@ -2430,6 +2464,10 @@ /* AT+VTX - Start sending */ if (!m->vpar[0]) PARSE_ERROR1; + if (info->online != 1) { + isdn_tty_modem_result(8, info); + return 1; + } info->dtmf_state = isdn_audio_dtmf_init(info->dtmf_state); if (!info->dtmf_state) { printk(KERN_WARNING "isdn_tty: Couldn't malloc dtmf state\n"); diff -ur --new-file old/linux/drivers/isdn/pcbit/callbacks.c new/linux/drivers/isdn/pcbit/callbacks.c --- old/linux/drivers/isdn/pcbit/callbacks.c Tue Apr 23 11:31:35 1996 +++ new/linux/drivers/isdn/pcbit/callbacks.c Sat Jun 29 19:36:22 1996 @@ -59,7 +59,8 @@ * - kfree when msg has been sent */ - if ((len = capi_conn_req(cbdata->data.setup.CalledPN, &skb)) < 0) + if ((len = capi_conn_req(cbdata->data.setup.CalledPN, &skb, + chan->proto)) < 0) { printk("capi_conn_req failed\n"); return; diff -ur --new-file old/linux/drivers/isdn/pcbit/capi.c new/linux/drivers/isdn/pcbit/capi.c --- old/linux/drivers/isdn/pcbit/capi.c Tue Apr 23 11:31:35 1996 +++ new/linux/drivers/isdn/pcbit/capi.c Sat Jun 29 19:36:22 1996 @@ -58,7 +58,7 @@ * */ -int capi_conn_req(const char * calledPN, struct sk_buff **skb) +int capi_conn_req(const char * calledPN, struct sk_buff **skb, int proto) { ushort len; @@ -80,6 +80,9 @@ len = 18 + strlen(calledPN); + if (proto == ISDN_PROTO_L2_TRANS) + len++; + if ((*skb = dev_alloc_skb(len)) == NULL) { printk(KERN_WARNING "capi_conn_req: alloc_skb failed\n"); @@ -89,11 +92,21 @@ /* InfoElmMask */ *((ushort*) skb_put(*skb, 2)) = AppInfoMask; - - /* Bearer Capability - Mandatory*/ - *(skb_put(*skb, 1)) = 2; /* BC0.Length */ - *(skb_put(*skb, 1)) = 0x88; /* BC0.Octect3 - Digital Information */ - *(skb_put(*skb, 1)) = 0x90; /* BC0.Octect4 - */ + if (proto == ISDN_PROTO_L2_TRANS) + { + /* Bearer Capability - Mandatory*/ + *(skb_put(*skb, 1)) = 3; /* BC0.Length */ + *(skb_put(*skb, 1)) = 0x80; /* Speech */ + *(skb_put(*skb, 1)) = 0x10; /* Circuit Mode */ + *(skb_put(*skb, 1)) = 0x23; /* A-law */ + } + else + { + /* Bearer Capability - Mandatory*/ + *(skb_put(*skb, 1)) = 2; /* BC0.Length */ + *(skb_put(*skb, 1)) = 0x88; /* Digital Information */ + *(skb_put(*skb, 1)) = 0x90; /* BC0.Octect4 */ + } /* Bearer Capability - Optional*/ *(skb_put(*skb, 1)) = 0; /* BC1.Length = 0 */ @@ -220,16 +233,19 @@ *(skb_put(*skb, 1)) = 0x05; /* LAPB */ break; case ISDN_PROTO_L2_HDLC: -#ifdef DEBUG - printk(KERN_DEBUG "HDLC\n"); /* HDLC */ -#endif *(skb_put(*skb, 1)) = 0x02; break; + case ISDN_PROTO_L2_TRANS: + /* + * Voice (a-law) + */ + *(skb_put(*skb, 1)) = 0x06; + break; default: #ifdef DEBUG printk(KERN_DEBUG "Transparent\n"); #endif - *(skb_put(*skb, 1)) = 0x03; + *(skb_put(*skb, 1)) = 0x03; break; } diff -ur --new-file old/linux/drivers/isdn/pcbit/capi.h new/linux/drivers/isdn/pcbit/capi.h --- old/linux/drivers/isdn/pcbit/capi.h Tue Apr 23 11:31:35 1996 +++ new/linux/drivers/isdn/pcbit/capi.h Sat Jun 29 19:36:22 1996 @@ -22,7 +22,8 @@ #define AppInfoMask REQ_CAUSE|REQ_DISPLAY|REQ_USER_TO_USER /* Connection Setup */ -extern int capi_conn_req(const char * calledPN, struct sk_buff **buf); +extern int capi_conn_req(const char * calledPN, struct sk_buff **buf, + int proto); extern int capi_decode_conn_conf(struct pcbit_chan * chan, struct sk_buff *skb, int *complete); diff -ur --new-file old/linux/drivers/isdn/pcbit/drv.c new/linux/drivers/isdn/pcbit/drv.c --- old/linux/drivers/isdn/pcbit/drv.c Sun May 19 14:29:30 1996 +++ new/linux/drivers/isdn/pcbit/drv.c Sat Jun 29 19:36:22 1996 @@ -11,6 +11,14 @@ * PCBIT-D interface with isdn4linux */ +/* + * Fixes: + * + * Nuno Grilo + * fixed msn_list NULL pointer dereference. + * + */ + #define __NO_VERSION__ #include @@ -109,7 +117,7 @@ dev->b2->id = 1; - dev->qdelivery.next = 0; + dev->qdelivery.next = NULL; dev->qdelivery.sync = 0; dev->qdelivery.routine = pcbit_deliver; dev->qdelivery.data = dev; @@ -152,8 +160,8 @@ dev_if->channels = 2; - dev_if->features = ISDN_FEATURE_P_EURO | ISDN_FEATURE_L3_TRANS | - ISDN_FEATURE_L2_HDLC; + dev_if->features = (ISDN_FEATURE_P_EURO | ISDN_FEATURE_L3_TRANS | + ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L2_TRANS ); dev_if->writebuf_skb = pcbit_xmit; dev_if->writebuf = NULL; @@ -1051,7 +1059,8 @@ static void pcbit_set_msn(struct pcbit_dev *dev, char *list) { - struct msn_entry *ptr, *back; + struct msn_entry *ptr; + struct msn_entry *back = NULL; char *cp, *sp; int len; @@ -1070,7 +1079,8 @@ return; } - for (back=dev->msn_list; back->next; back=back->next); + if (dev->msn_list) + for (back=dev->msn_list; back->next; back=back->next); sp = list; @@ -1128,10 +1138,3 @@ return 0; } - - - - - - - diff -ur --new-file old/linux/drivers/isdn/pcbit/edss1.c new/linux/drivers/isdn/pcbit/edss1.c --- old/linux/drivers/isdn/pcbit/edss1.c Tue Apr 23 11:31:35 1996 +++ new/linux/drivers/isdn/pcbit/edss1.c Thu Aug 1 14:43:04 1996 @@ -288,22 +288,23 @@ save_flags(flags); cli(); - if (chan->fsm_timer.function) { - del_timer(&chan->fsm_timer); - chan->fsm_timer.function = NULL; - } for (action = fsm_table; action->init != 0xff; action++) if (action->init == chan->fsm_state && action->event == event) break; - if (action->init == 0xff) { printk(KERN_DEBUG "fsm error: event %x on state %x\n", event, chan->fsm_state); + restore_flags(flags); return; } + + if (chan->fsm_timer.function) { + del_timer(&chan->fsm_timer); + chan->fsm_timer.function = NULL; + } chan->fsm_state = action->final; diff -ur --new-file old/linux/drivers/isdn/pcbit/layer2.c new/linux/drivers/isdn/pcbit/layer2.c --- old/linux/drivers/isdn/pcbit/layer2.c Tue Apr 23 11:31:35 1996 +++ new/linux/drivers/isdn/pcbit/layer2.c Sat Jun 29 19:36:22 1996 @@ -58,16 +58,7 @@ /* * task queue struct */ -struct tq_struct *tq_delivery=NULL; -static void do_pcbit_bh(task_queue *list) -{ - run_task_queue(list); -} - -struct tq_struct run_delivery= { - 0, 0, (void *)(void *) do_pcbit_bh, &tq_delivery, -}; /* @@ -87,7 +78,6 @@ static void pcbit_transmit(struct pcbit_dev * dev); static void pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack); -static void pcbit_frame_read(struct pcbit_dev * dev, unsigned char read_seq); static void pcbit_l2_error(struct pcbit_dev *dev); static void pcbit_l2_active_conf(struct pcbit_dev *dev, u_char info); @@ -95,11 +85,10 @@ static void pcbit_firmware_bug(struct pcbit_dev * dev); -static void pcbit_sched_delivery(struct pcbit_dev *dev) +static __inline__ void pcbit_sched_delivery(struct pcbit_dev *dev) { - queue_task_irq_off(&dev->qdelivery, &tq_delivery); - queue_task_irq_off(&run_delivery, &tq_immediate); - mark_bh(IMMEDIATE_BH); + queue_task(&dev->qdelivery, &tq_immediate); + mark_bh(IMMEDIATE_BH); } @@ -195,11 +184,10 @@ unacked = (dev->send_seq + (8 - dev->unack_seq) ) & 0x07; - if (dev->free > 16 && dev->write_queue && unacked < 7) { - - save_flags(flags); - cli(); + save_flags(flags); + cli(); + if (dev->free > 16 && dev->write_queue && unacked < 7) { if (!dev->w_busy) dev->w_busy = 1; @@ -209,11 +197,12 @@ return; } - restore_flags(flags); frame = dev->write_queue; free = dev->free; + restore_flags(flags); + if (frame->copied == 0) { /* Type 0 frame */ @@ -311,12 +300,15 @@ dev->w_busy = 0; restore_flags(flags); } -#ifdef DEBUG else + { + restore_flags(flags); +#ifdef DEBUG printk(KERN_DEBUG "unacked %d free %d write_queue %s\n", unacked, dev->free, dev->write_queue ? "not empty" : - "empty"); + "empty"); #endif + } } @@ -334,29 +326,31 @@ save_flags(flags); cli(); - /* get frame from queue */ - if (!(frame=dev->read_queue)) { + while((frame=dev->read_queue)) + { + dev->read_queue = frame->next; restore_flags(flags); - return; - } - dev->read_queue = frame->next; - restore_flags(flags); + msg.cpu = 0; + msg.proc = 0; + msg.cmd = frame->skb->data[2]; + msg.scmd = frame->skb->data[3]; - msg.cpu = 0; - msg.proc = 0; - msg.cmd = frame->skb->data[2]; - msg.scmd = frame->skb->data[3]; + frame->refnum = *((ushort*) frame->skb->data + 4); + frame->msg = *((ulong*) &msg); + + skb_pull(frame->skb, 6); - frame->refnum = *((ushort*) frame->skb->data + 4); - frame->msg = *((ulong*) &msg); - - skb_pull(frame->skb, 6); + pcbit_l3_receive(dev, frame->msg, frame->skb, frame->hdr_len, + frame->refnum); - pcbit_l3_receive(dev, frame->msg, frame->skb, frame->hdr_len, - frame->refnum); + kfree(frame); - kfree(frame); + save_flags(flags); + cli(); + } + + restore_flags(flags); } /* @@ -517,8 +511,7 @@ } else dev->read_queue = frame; - - pcbit_sched_delivery(dev); + restore_flags(flags); } @@ -572,7 +565,6 @@ { struct pcbit_dev * dev; u_char info, ack_seq, read_seq; - u_char ack_int = 1; dev = (struct pcbit_dev *) devptr; @@ -618,33 +610,27 @@ read_seq = (info & 0x07U); dev->interrupt = 0; - sti(); - - /* - * Bottom Half - * Runs with ints enabled - */ if (read_seq != dev->rcv_seq) { - pcbit_frame_read(dev, read_seq); - ack_int = 0; + while (read_seq != dev->rcv_seq) + { + pcbit_receive(dev); + dev->rcv_seq = (dev->rcv_seq + 1) % 8; + } + pcbit_sched_delivery(dev); } if (ack_seq != dev->unack_seq) { pcbit_recv_ack(dev, ack_seq); - ack_int = 0; } - if (ack_int) - { - info = 0; - info |= dev->rcv_seq << 3; - info |= dev->send_seq; + + info = dev->rcv_seq << 3; + info |= dev->send_seq; - writeb(info, dev->sh_mem + BANK4); - } + writeb(info, dev->sh_mem + BANK4); } @@ -685,17 +671,19 @@ del_timer(&dev->error_recover_timer); if (dev->w_busy || dev->r_busy) - { - init_timer(&dev->error_recover_timer); - dev->error_recover_timer.expires = jiffies + ERRTIME; - add_timer(&dev->error_recover_timer); - return; - } + { + init_timer(&dev->error_recover_timer); + dev->error_recover_timer.expires = jiffies + ERRTIME; + add_timer(&dev->error_recover_timer); + return; + } dev->w_busy = dev->r_busy = 1; - if (dev->read_frame) { - if (dev->read_frame->skb) { + if (dev->read_frame) + { + if (dev->read_frame->skb) + { dev->read_frame->skb->free = 1; kfree_skb(dev->read_frame->skb, FREE_READ); } @@ -704,7 +692,8 @@ } - if (dev->write_queue) { + if (dev->write_queue) + { frame = dev->write_queue; #ifdef FREE_ON_ERROR dev->write_queue = dev->write_queue->next; @@ -775,14 +764,20 @@ { if (dev->send_seq > dev->unack_seq) - if (ack <= dev->unack_seq || ack > dev->send_seq) + if (ack <= dev->unack_seq || ack > dev->send_seq) { - printk("layer 2 ack unacceptable - dev %d", dev->id); + printk(KERN_DEBUG + "layer 2 ack unacceptable - dev %d", + dev->id); + pcbit_l2_error(dev); } else - if (ack > dev->send_seq && ack <= dev->unack_seq) { - printk("layer 2 ack unacceptable - dev %d", dev->id); + if (ack > dev->send_seq && ack <= dev->unack_seq) + { + printk(KERN_DEBUG + "layer 2 ack unacceptable - dev %d", + dev->id); pcbit_l2_error(dev); } @@ -805,55 +800,9 @@ if (dev->send_seq == lsend_seq) break; - count++; - } - - if (!count) { - u_char info; - - info = 0; - info |= dev->rcv_seq << 3; - info |= dev->send_seq; - - writeb(info, dev->sh_mem + BANK4); - } + count++; + } } else printk(KERN_DEBUG "recv_ack: unacked = 0\n"); } - -static void pcbit_frame_read(struct pcbit_dev * dev, unsigned char read_seq) -{ - unsigned long flags; - int busy; - u_char info; - - save_flags(flags); - cli(); - if (!(busy=dev->r_busy)) - dev->r_busy = 1; - restore_flags(flags); - - if (busy) - return; - - - while (read_seq != dev->rcv_seq) { - pcbit_receive(dev); - dev->rcv_seq = (dev->rcv_seq + 1) % 8; - } - - dev->r_busy = 0; - - info = 0; - info |= dev->rcv_seq << 3; - info |= dev->send_seq; - - writeb(info, dev->sh_mem + BANK4); -} - - - - - - diff -ur --new-file old/linux/drivers/isdn/teles/callc.c new/linux/drivers/isdn/teles/callc.c --- old/linux/drivers/isdn/teles/callc.c Fri Jun 7 15:02:41 1996 +++ new/linux/drivers/isdn/teles/callc.c Sat Jun 29 19:36:23 1996 @@ -1,6 +1,12 @@ -/* $Id: callc.c,v 1.11 1996/06/07 12:32:20 fritz Exp $ +/* $Id: callc.c,v 1.13 1996/06/24 17:15:55 fritz Exp $ * * $Log: callc.c,v $ + * Revision 1.13 1996/06/24 17:15:55 fritz + * corrected return code of teles_writebuf() + * + * Revision 1.12 1996/06/12 16:15:33 fritz + * Extended user-configurable debugging flags. + * * Revision 1.11 1996/06/07 12:32:20 fritz * More changes to support suspend/resume. * @@ -1297,8 +1303,10 @@ chanlist[i].ds.l2.l2m.debug = debugflags & 16; } for (i = 0; i < nrcards; i++) - if (cards[i].sp) + if (cards[i].sp) { cards[i].sp->dlogflag = debugflags & 4; + cards[i].sp->debug = debugflags & 32; + } } int @@ -1419,12 +1427,15 @@ if (!chanp->data_open) { printk(KERN_DEBUG "teles_writebuf: channel not open\n"); - return -ENOMEM; + return -EIO; } err = BufPoolGet(&ibh, st->l1.sbufpool, GFP_ATOMIC, st, 21); if (err) - return -ENOMEM; + /* Must return 0 here, since this is not an error + * but a temporary lack of resources. + */ + return 0; ptr = DATAPTR(ibh); if (chanp->lc_b.l2_establish) diff -ur --new-file old/linux/drivers/isdn/teles/card.c new/linux/drivers/isdn/teles/card.c --- old/linux/drivers/isdn/teles/card.c Fri Jun 7 15:02:42 1996 +++ new/linux/drivers/isdn/teles/card.c Sat Jun 29 19:36:23 1996 @@ -1,4 +1,4 @@ -/* $Id: card.c,v 1.9 1996/06/06 14:42:09 fritz Exp $ +/* $Id: card.c,v 1.12 1996/06/24 17:16:52 fritz Exp $ * * card.c low level stuff for the Teles S0 isdn card * @@ -7,6 +7,16 @@ * Beat Doebeli log all D channel traffic * * $Log: card.c,v $ + * Revision 1.12 1996/06/24 17:16:52 fritz + * Added check for misconfigured membase. + * + * Revision 1.11 1996/06/14 03:30:37 fritz + * Added recovery from EXIR 40 interrupt. + * Some cleanup. + * + * Revision 1.10 1996/06/11 14:57:20 hipp + * minor changes to ensure, that SKBs are sent in the right order + * * Revision 1.9 1996/06/06 14:42:09 fritz * Bugfix: forgot hsp-> in last change. * @@ -52,7 +62,6 @@ #include #undef DCHAN_VERBOSE -#define FRITZ_EXPERIMENTAL extern void tei_handler(struct PStack *st, byte pr, struct BufHeader *ibh); @@ -215,16 +224,9 @@ static inline void waitforXFW_0(byte * base, byte hscx) { -#ifdef FRITZ_EXPERIMENTAL long to = 20; while ((!(readhscx_0(base, hscx, HSCX_STAR) & 0x44)==0x40) && to) { -#else - long to = 10; - - waitforCEC_0(base, hscx); - while ((!(readhscx_0(base, hscx, HSCX_STAR) & 0x40)) && to) { -#endif udelay(5); to--; } @@ -235,16 +237,9 @@ static inline void waitforXFW_3(int iobase, byte hscx) { -#ifdef FRITZ_EXPERIMENTAL long to = 20; while ((!(readhscx_3(iobase, hscx, HSCX_STAR) & 0x44)==0x40) && to) { -#else - long to = 10; - - waitforCEC_3(iobase, hscx); - while ((!(readhscx_3(iobase, hscx, HSCX_STAR) & 0x40)) && to) { -#endif udelay(5); to--; } @@ -507,10 +502,10 @@ } else { if (hsp->releasebuf) BufPoolRelease(hsp->xmtibh); - hsp->xmtibh = NULL; hsp->sendptr = 0; if (hsp->st->l4.l1writewakeup) hsp->st->l4.l1writewakeup(hsp->st); + hsp->xmtibh = NULL; } if (!BufQueueUnlink(&hsp->xmtibh, &hsp->sq)) { hsp->releasebuf = !0; @@ -709,7 +704,7 @@ static void teles_interrupt(int intno, void *dev_id, struct pt_regs *regs) { - byte val, val2, r, exval; + byte val, r, exval; struct IsdnCardState *sp; unsigned int count; struct HscxState *hsp; @@ -725,11 +720,20 @@ if (val & 0x01) { hsp = sp->hs + 1; exval = READHSCX(sp->membase, sp->iobase, 1, HSCX_EXIR); - if ((hsp->mode == 1) || (exval == 0x40)) - hscx_fill_fifo(hsp); - else - printk(KERN_WARNING "HSCX B EXIR %x xmitbh %lx rcvibh %lx\n", - exval, (long) hsp->xmtibh, (long) hsp->rcvibh); + if (exval == 0x40) { + if (hsp->mode == 1) + hscx_fill_fifo(hsp); + else { + /* Here we lost an TX interrupt, so + * restart transmitting the whole frame. + */ + hsp->sendptr = 0; + WRITEHSCX_CMDR(hsp->membase, hsp->iobase, + hsp->hscx, 0x01); + printk(KERN_DEBUG "HSCX B EXIR %x\n", exval); + } + } else + printk(KERN_WARNING "HSCX B EXIR %x\n", exval); } if (val & 0xf8) { if (sp->debug) @@ -739,33 +743,28 @@ if (val & 0x02) { hsp = sp->hs; exval = READHSCX(sp->membase, sp->iobase, 0, HSCX_EXIR); - if ((hsp->mode == 1) && (exval == 0x40)) - hscx_fill_fifo(hsp); - else - printk(KERN_WARNING "HSCX A EXIR %x\n",exval); + if (exval == 0x40) { + if (hsp->mode == 1) + hscx_fill_fifo(hsp); + else { + /* Here we lost an TX interrupt, so + * restart transmitting the whole frame. + */ + hsp->sendptr = 0; + WRITEHSCX_CMDR(hsp->membase, hsp->iobase, + hsp->hscx, 0x01); + printk(KERN_DEBUG "HSCX A EXIR %x\n", exval); + } + } else + printk(KERN_WARNING "HSCX A EXIR %x\n", exval); } - -/* ??? Why do that vvvvvvvvvvvvvvvvvvvvv different on Teles 16-3 ??? */ - if (sp->membase) { - if (val & 0x04) { - val = readhscx_0(sp->membase, 0, HSCX_ISTA); - if (sp->debug) - printk(KERN_DEBUG "HSCX A interrupt %x\n", - val); - hscx_interrupt(sp, val, 0); - } - } else { - val2 = readhscx_3(sp->iobase, 0, HSCX_ISTA); + if (val & 0x04) { + val = READHSCX(sp->membase, sp->iobase, 0, HSCX_ISTA); if (sp->debug) - printk(KERN_DEBUG "HSCX A ISTA %x\n", val2); - if (val & 0x04) { - if (sp->debug) - printk(KERN_DEBUG "HSCX A interrupt %x\n", - val2); - hscx_interrupt(sp, val2, 0); - } + printk(KERN_DEBUG "HSCX A interrupt %x\n", + val); + hscx_interrupt(sp, val, 0); } -/* ??? Why do that ^^^^^^^^^^^^^^^^^^^^^ different on Teles 16-3 ??? */ val = READISAC(sp->membase, sp->iobase, ISAC_ISTA); @@ -1083,6 +1082,13 @@ byte cfval, val; struct IsdnCard *card = cards + cardnr; + if (card->membase) + if ((unsigned long)card->membase < 0x10000) { + (unsigned long)card->membase <<= 4; + printk(KERN_INFO + "Teles membase configured DOSish, assuming 0x%lx\n", + (unsigned long)card->membase); + } if (!card->iobase) { if (card->membase) { printk(KERN_NOTICE @@ -1090,7 +1096,7 @@ (long) card->membase, card->interrupt, (card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" : "EDSS1"); - printk(KERN_INFO "HSCX version A: %x B:%x\n", + printk(KERN_INFO "HSCX version A:%x B:%x\n", readhscx_0(card->membase, 0, HSCX_VSTR) & 0xf, readhscx_0(card->membase, 1, HSCX_VSTR) & 0xf); } @@ -1736,12 +1742,18 @@ struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware; struct HscxState *hsp = sp->hs + st->l1.hscx; + long flags; switch (pr) { case (PH_DATA): - if (hsp->xmtibh) + save_flags(flags); + cli(); + if (hsp->xmtibh) { BufQueueLink(&hsp->sq, ibh); + restore_flags(flags); + } else { + restore_flags(flags); hsp->xmtibh = ibh; hsp->sendptr = 0; hsp->releasebuf = !0; diff -ur --new-file old/linux/drivers/net/3c505.c new/linux/drivers/net/3c505.c --- old/linux/drivers/net/3c505.c Wed Apr 17 06:20:07 1996 +++ new/linux/drivers/net/3c505.c Thu Aug 1 14:43:04 1996 @@ -491,7 +491,6 @@ return TRUE; break; case ASF_PCB_NAK: - cli(); printk("%s: send_pcb got NAK\n", dev->name); goto abort; break; diff -ur --new-file old/linux/drivers/net/3c509.c new/linux/drivers/net/3c509.c --- old/linux/drivers/net/3c509.c Wed May 15 08:09:00 1996 +++ new/linux/drivers/net/3c509.c Sun Aug 18 10:22:50 1996 @@ -47,11 +47,11 @@ #include #include #include /* for CONFIG_MCA */ +#include /* for udelay() */ #include #include - #ifdef EL3_DEBUG int el3_debug = EL3_DEBUG; #else @@ -310,28 +310,24 @@ */ static ushort read_eeprom(short ioaddr, int index) { - int timer; - outw(EEPROM_READ + index, ioaddr + 10); /* Pause for at least 162 us. for the read to take place. */ - for (timer = 0; timer < 162*4 + 400; timer++) - SLOW_DOWN_IO; + udelay (200); return inw(ioaddr + 12); } /* Read a word from the EEPROM when in the ISA ID probe state. */ static ushort id_read_eeprom(int index) { - int timer, bit, word = 0; + int bit, word = 0; /* Issue read command, and pause for at least 162 us. for it to complete. Assume extra-fast 16Mhz bus. */ outb(EEPROM_READ + index, id_port); - /* This should really be done by looking at one of the timer channels. */ - for (timer = 0; timer < 162*4 + 400; timer++) - SLOW_DOWN_IO; - + /* Pause for at least 162 us. for the read to take place. */ + udelay (200); + for (bit = 15; bit >= 0; bit--) word = (word << 1) + (inb(id_port) & 0x01); @@ -430,7 +426,7 @@ /* Transmitter timeout, serious problems. */ if (dev->tbusy) { int tickssofar = jiffies - dev->trans_start; - if (tickssofar < 40) + if (tickssofar < 40*HZ/100) return 1; printk("%s: transmit timed out, Tx_status %2.2x status %4.4x " "Tx FIFO room %d.\n", diff -ur --new-file old/linux/drivers/net/3c59x.c new/linux/drivers/net/3c59x.c --- old/linux/drivers/net/3c59x.c Tue Apr 16 14:37:55 1996 +++ new/linux/drivers/net/3c59x.c Thu Jul 18 09:08:45 1996 @@ -7,24 +7,24 @@ This driver is for the 3Com "Vortex" series ethercards. Members of the series include the 3c590 PCI EtherLink III and 3c595-Tx PCI Fast - EtherLink. It also works with the 10Mbs-only 3c590 PCI EtherLink III. + EtherLink. The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O Center of Excellence in Space Data and Information Sciences Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 */ -static char *version = "3c59x.c:v0.13 2/13/96 becker@cesdis.gsfc.nasa.gov\n"; +static char *version = "3c59x.c:v0.25 5/17/96 becker@cesdis.gsfc.nasa.gov\n"; /* "Knobs" that turn on special features. */ +/* Enable the experimental automatic media selection code. */ +#define AUTOMEDIA 1 + /* Allow the use of bus master transfers instead of programmed-I/O for the Tx process. Bus master transfers are always disabled by default, but iff this is set they may be turned on using 'options'. */ #define VORTEX_BUS_MASTER -/* Put out somewhat more debugging messages. (0 - no msg, 1 minimal msgs). */ -#define VORTEX_DEBUG 1 - #include #include @@ -46,10 +46,23 @@ #include #include -#ifdef HAVE_SHARED_IRQ -#define USE_SHARED_IRQ -#include -#endif +#define RUN_AT(x) (jiffies + (x)) +#define DEV_ALLOC_SKB(len) dev_alloc_skb(len + 2) + +#define FREE_IRQ(irqnum, dev) free_irq(irqnum, dev) +#define REQUEST_IRQ(i,h,f,n, instance) request_irq(i,h,f,n, instance) +#define IRQ(irq, dev_id, pt_regs) (irq, dev_id, pt_regs) + +/* "Knobs" for adjusting internal parameters. */ +/* Put out somewhat more debugging messages. (0 - no msg, 1 minimal msgs). */ +#define VORTEX_DEBUG 2 + +/* Number of times to check to see if the Tx FIFO has space, used in some + limited cases. */ +#define WAIT_TX_AVAIL 200 + +/* Operational parameter that usually are not changed. */ +#define TX_TIMEOUT 40 /* Time in jiffies before concluding Tx hung */ /* The total size is twice that of the original EtherLinkIII series: the runtime register window, window 1, is now always mapped in. */ @@ -117,8 +130,8 @@ Thanks to Cameron Spitzer and Terry Murphy of 3Com for providing both 3c590 and 3c595 boards. The name "Vortex" is the internal 3Com project name for the PCI ASIC, and -the not-yet-released (3/95) EISA version is called "Demon". According to -Terry these names come from rides at the local amusement park. +the EISA version is called "Demon". According to Terry these names come +from rides at the local amusement park. The new chips support both ethernet (1.5K) and FDDI (4.5K) packet sizes! This driver only supports ethernet packets because of the skbuff allocation @@ -176,6 +189,7 @@ }; enum Window0 { Wn0EepromCmd = 10, /* Window 0: EEPROM command register. */ + Wn0EepromData = 12, /* Window 0: EEPROM results register. */ }; enum Win0_EEPROM_bits { EEPROM_Read = 0x80, EEPROM_WRITE = 0x40, EEPROM_ERASE = 0xC0, @@ -206,7 +220,10 @@ Wn4_Media = 0x0A, /* Window 4: Various transcvr/media bits. */ }; enum Win4_Media_bits { - Media_TP = 0x00C0, /* Enable link beat and jabber for 10baseT. */ + Media_SQE = 0x0008, /* Enable SQE error counting for AUI. */ + Media_10TP = 0x00C0, /* Enable link beat and jabber for 10baseT. */ + Media_Lnk = 0x0080, /* Enable just link beat for 100TX/100FX. */ + Media_LnkBeat = 0x0800, }; enum Window7 { /* Window 7: Bus Master control. */ Wn7_MasterAddr = 0, Wn7_MasterLen = 6, Wn7_MasterStatus = 12, @@ -217,17 +234,36 @@ const char *product_name; struct device *next_module; struct enet_statistics stats; -#ifdef VORTEX_BUS_MASTER struct sk_buff *tx_skb; /* Packet being eaten by bus master ctrl. */ -#endif struct timer_list timer; /* Media selection timer. */ - int options; /* User-settable driver options (none yet). */ - unsigned int media_override:3, full_duplex:1, bus_master:1, autoselect:1; + int options; /* User-settable misc. driver options. */ + int last_rx_packets; /* For media autoselection. */ + unsigned int available_media:8, /* From Wn3_Options */ + media_override:3, /* Passed-in media type. */ + default_media:3, /* Read from the EEPROM. */ + full_duplex:1, bus_master:1, autoselect:1; }; -static char *if_names[] = { - "10baseT", "10Mbs AUI", "undefined", "10base2", - "100baseTX", "100baseFX", "MII", "undefined"}; +/* The action to take with a media selection timer tick. + Note that we deviate from the 3Com order by checking 10base2 before AUI. + */ +static struct media_table { + char *name; + unsigned int media_bits:16, /* Bits to set in Wn4_Media register. */ + mask:8, /* The transceiver-present bit in Wn3_Config.*/ + next:8; /* The media type to try next. */ + short wait; /* Time before we check media status. */ +} media_tbl[] = { + { "10baseT", Media_10TP,0x08, 3 /* 10baseT->10base2 */, (14*HZ)/10}, + { "10Mbs AUI", Media_SQE, 0x20, 8 /* AUI->default */, (1*HZ)/10}, + { "undefined", 0, 0x80, 0 /* Undefined */, 0}, + { "10base2", 0, 0x10, 1 /* 10base2->AUI. */, (1*HZ)/10}, + { "100baseTX", Media_Lnk, 0x02, 5 /* 100baseTX->100baseFX */, (14*HZ)/10}, + { "100baseFX", Media_Lnk, 0x04, 6 /* 100baseFX->MII */, (14*HZ)/10}, + { "MII", 0, 0x40, 0 /* MII->10baseT */, (14*HZ)/10}, + { "undefined", 0, 0x01, 0 /* Undefined/100baseT4 */, 0}, + { "Default", 0, 0xFF, 0 /* Use default */, 0}, +}; static int vortex_scan(struct device *dev); static int vortex_found_device(struct device *dev, int ioaddr, int irq, @@ -237,11 +273,11 @@ static void vortex_timer(unsigned long arg); static int vortex_start_xmit(struct sk_buff *skb, struct device *dev); static int vortex_rx(struct device *dev); -static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs); static int vortex_close(struct device *dev); static void update_stats(int addr, struct device *dev); static struct enet_statistics *vortex_get_stats(struct device *dev); -static void set_multicast_list(struct device *dev); +static void set_rx_mode(struct device *dev); /* Unlike the other PCI cards the 59x cards don't need a large contiguous @@ -260,7 +296,7 @@ */ /* This driver uses 'options' to pass the media type, full-duplex flag, etc. */ /* Note: this is the only limit on the number of cards supported!! */ -int options[8] = { -1, -1, -1, -1, -1, -1, -1, -1,}; +static int options[8] = { -1, -1, -1, -1, -1, -1, -1, -1,}; #ifdef MODULE static int debug = -1; @@ -283,7 +319,7 @@ } #else -unsigned long tc59x_probe(struct device *dev) +int tc59x_probe(struct device *dev) { int cards_found = 0; @@ -302,55 +338,54 @@ if (pcibios_present()) { static int pci_index = 0; - for (; pci_index < 8; pci_index++) { - unsigned char pci_bus, pci_device_fn, pci_irq_line, pci_latency; - unsigned int pci_ioaddr; - unsigned short pci_command; - int index; - - for (index = 0; product_ids[index]; index++) { - if ( ! pcibios_find_device(TCOM_VENDOR_ID, product_ids[index], - pci_index, &pci_bus, - &pci_device_fn)) + static int board_index = 0; + for (; product_ids[board_index]; board_index++, pci_index = 0) { + for (; pci_index < 16; pci_index++) { + unsigned char pci_bus, pci_device_fn, pci_irq_line; + unsigned char pci_latency; + unsigned int pci_ioaddr; + unsigned short pci_command; + + if (pcibios_find_device(TCOM_VENDOR_ID, + product_ids[board_index], pci_index, + &pci_bus, &pci_device_fn)) break; - } - if ( ! product_ids[index]) - break; - - pcibios_read_config_byte(pci_bus, pci_device_fn, - PCI_INTERRUPT_LINE, &pci_irq_line); - pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_0, &pci_ioaddr); - /* Remove I/O space marker in bit 0. */ - pci_ioaddr &= ~3; + pcibios_read_config_byte(pci_bus, pci_device_fn, + PCI_INTERRUPT_LINE, &pci_irq_line); + pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_0, &pci_ioaddr); + /* Remove I/O space marker in bit 0. */ + pci_ioaddr &= ~3; #ifdef VORTEX_BUS_MASTER - /* Get and check the bus-master and latency values. - Some PCI BIOSes fail to set the master-enable bit, and - the latency timer must be set to the maximum value to avoid - data corruption that occurs when the timer expires during - a transfer. Yes, it's a bug. */ - 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, + /* Get and check the bus-master and latency values. + Some PCI BIOSes fail to set the master-enable bit, and + the latency timer must be set to the maximum value to avoid + data corruption that occurs when the timer expires during + a transfer. Yes, it's a bug. */ + 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 != 255) { - printk(" Overriding PCI latency timer (CFLT) setting of %d, new value is 255.\n", pci_latency); - pcibios_write_config_byte(pci_bus, pci_device_fn, - PCI_LATENCY_TIMER, 255); - } + if (pci_latency != 255) { + printk(" Overriding PCI latency timer (CFLT) setting of" + " %d, new value is 255.\n", pci_latency); + pcibios_write_config_byte(pci_bus, pci_device_fn, + PCI_LATENCY_TIMER, 255); + } #endif /* VORTEX_BUS_MASTER */ - vortex_found_device(dev, pci_ioaddr, pci_irq_line, index, - dev && dev->mem_start ? dev->mem_start - : options[cards_found]); - dev = 0; - cards_found++; + vortex_found_device(dev, pci_ioaddr, pci_irq_line, board_index, + dev && dev->mem_start ? dev->mem_start + : options[cards_found]); + dev = 0; + cards_found++; + } } } @@ -361,9 +396,9 @@ /* Check the standard EISA ID register for an encoded '3Com'. */ if (inw(ioaddr + 0xC80) != 0x6d50) continue; - /* Check for a product that we support. */ - if ((inw(ioaddr + 0xC82) & 0xFFF0) != 0x5970 - && (inw(ioaddr + 0xC82) & 0xFFF0) != 0x5920) + /* Check for a product that we support, 3c59{2,7} any rev. */ + if ((inw(ioaddr + 0xC82) & 0xF0FF) != 0x7059 /* 597 */ + && (inw(ioaddr + 0xC82) & 0xF0FF) != 0x2059) /* 592 */ continue; vortex_found_device(dev, ioaddr, inw(ioaddr + 0xC88) >> 12, DEMON_INDEX, dev && dev->mem_start @@ -452,12 +487,12 @@ int timer; outw(EEPROM_Read + PhysAddr01 + i, ioaddr + Wn0EepromCmd); /* Pause for at least 162 us. for the read to take place. */ - for (timer = 0; timer < 162*4 + 400; timer++) { + for (timer = 162*4 + 400; timer >= 0; timer--) { SLOW_DOWN_IO; if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0) break; } - phys_addr[i] = htons(inw(ioaddr + 12)); + phys_addr[i] = htons(inw(ioaddr + Wn0EepromData)); } for (i = 0; i < 6; i++) printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]); @@ -470,6 +505,7 @@ char *ram_split[] = {"5:3", "3:1", "1:1", "invalid"}; union wn3_config config; EL3WINDOW(3); + vp->available_media = inw(ioaddr + Wn3_Options); config.i = inl(ioaddr + Wn3_Config); if (vortex_debug > 1) printk(" Internal config register is %4.4x, transceivers %#x.\n", @@ -479,8 +515,9 @@ config.u.ram_width ? "word" : "byte", ram_split[config.u.ram_split], config.u.autoselect ? "autoselect/" : "", - if_names[config.u.xcvr]); + media_tbl[config.u.xcvr].name); dev->if_port = config.u.xcvr; + vp->default_media = config.u.xcvr; vp->autoselect = config.u.autoselect; } @@ -492,10 +529,7 @@ dev->hard_start_xmit = &vortex_start_xmit; dev->stop = &vortex_close; dev->get_stats = &vortex_get_stats; - dev->set_multicast_list = &set_multicast_list; -#if defined (HAVE_SET_MAC_ADDR) && 0 - dev->set_mac_address = &set_mac_address; -#endif + dev->set_multicast_list = &set_rx_mode; return 0; } @@ -518,11 +552,29 @@ if (vp->media_override != 7) { if (vortex_debug > 1) printk("%s: Media override to transceiver %d (%s).\n", - dev->name, vp->media_override, if_names[vp->media_override]); - config.u.xcvr = vp->media_override; + dev->name, vp->media_override, + media_tbl[vp->media_override].name); dev->if_port = vp->media_override; - outl(config.i, ioaddr + Wn3_Config); - } + } else if (vp->autoselect) { + /* Find first available media type, starting with 100baseTx. */ + dev->if_port = 4; + while (! (vp->available_media & media_tbl[dev->if_port].mask)) + dev->if_port = media_tbl[dev->if_port].next; + + if (vortex_debug > 1) + printk("%s: Initial media type %s.\n", + dev->name, media_tbl[dev->if_port].name); + + init_timer(&vp->timer); + vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait); + vp->timer.data = (unsigned long)dev; + vp->timer.function = &vortex_timer; /* timer handler */ + add_timer(&vp->timer); + } else + dev->if_port = vp->default_media; + + config.u.xcvr = dev->if_port; + outl(config.i, ioaddr + Wn3_Config); if (vortex_debug > 1) { printk("%s: vortex_open() InternalConfig %8.8x.\n", @@ -542,19 +594,11 @@ outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD); -#ifdef USE_SHARED_IRQ - i = request_shared_irq(dev->irq, &vortex_interrupt, dev, vp->product_name); - if (i) /* Error */ - return i; -#else - if (dev->irq == 0 || irq2dev_map[dev->irq] != NULL) - return -EAGAIN; - irq2dev_map[dev->irq] = dev; - if (request_irq(dev->irq, &vortex_interrupt, 0, vp->product_name, NULL)) { - irq2dev_map[dev->irq] = NULL; + /* Use the now-standard shared IRQ implementation. */ + if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ, + vp->product_name, dev)) { return -EAGAIN; } -#endif if (vortex_debug > 1) { EL3WINDOW(4); @@ -572,11 +616,9 @@ if (dev->if_port == 3) /* Start the thinnet transceiver. We should really wait 50ms...*/ outw(StartCoax, ioaddr + EL3_CMD); - else if (dev->if_port == 0) { - /* 10baseT interface, enabled link beat and jabber check. */ - EL3WINDOW(4); - outw(inw(ioaddr + Wn4_Media) | Media_TP, ioaddr + Wn4_Media); - } + EL3WINDOW(4); + outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP|Media_SQE)) | + media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media); /* Switch to the stats window, and clear all stats by reading. */ outw(StatsDisable, ioaddr + EL3_CMD); @@ -592,8 +634,8 @@ /* Switch to register set 7 for normal use. */ EL3WINDOW(7); - /* Accept b-case and phys addr only. */ - outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD); + /* Set reciever mode: presumably accept b-case and phys addr only. */ + set_rx_mode(dev); outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ dev->tbusy = 0; @@ -610,26 +652,83 @@ outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull | DMADone, ioaddr + EL3_CMD); -#ifdef MODULE MOD_INC_USE_COUNT; -#endif - if (vp->autoselect) { - init_timer(&vp->timer); - vp->timer.expires = (14*HZ)/10; /* 1.4 sec. */ - vp->timer.data = (unsigned long)dev; - vp->timer.function = &vortex_timer; /* timer handler */ - add_timer(&vp->timer); - } return 0; } static void vortex_timer(unsigned long data) { +#ifdef AUTOMEDIA struct device *dev = (struct device *)data; - if (vortex_debug > 2) - printk("%s: Media selection timer tick happened.\n", dev->name); - /* ToDo: active media selection here! */ + struct vortex_private *vp = (struct vortex_private *)dev->priv; + int ioaddr = dev->base_addr; + unsigned long flags; + int ok = 0; + + if (vortex_debug > 1) + printk("%s: Media selection timer tick happened, %s.\n", + dev->name, media_tbl[dev->if_port].name); + + save_flags(flags); cli(); { + int old_window = inw(ioaddr + EL3_CMD) >> 13; + int media_status; + EL3WINDOW(4); + media_status = inw(ioaddr + Wn4_Media); + switch (dev->if_port) { + case 0: case 4: case 5: /* 10baseT, 100baseTX, 100baseFX */ + if (media_status & Media_LnkBeat) { + ok = 1; + if (vortex_debug > 1) + printk("%s: Media %s has link beat, %x.\n", + dev->name, media_tbl[dev->if_port].name, media_status); + } else if (vortex_debug > 1) + printk("%s: Media %s is has no link beat, %x.\n", + dev->name, media_tbl[dev->if_port].name, media_status); + + break; + default: /* Other media types handled by Tx timeouts. */ + if (vortex_debug > 1) + printk("%s: Media %s is has no indication, %x.\n", + dev->name, media_tbl[dev->if_port].name, media_status); + ok = 1; + } + if ( ! ok) { + union wn3_config config; + + do { + dev->if_port = media_tbl[dev->if_port].next; + } while ( ! (vp->available_media & media_tbl[dev->if_port].mask)); + if (dev->if_port == 8) { /* Go back to default. */ + dev->if_port = vp->default_media; + if (vortex_debug > 1) + printk("%s: Media selection failing, using default %s port.\n", + dev->name, media_tbl[dev->if_port].name); + } else { + if (vortex_debug > 1) + printk("%s: Media selection failed, now trying %s port.\n", + dev->name, media_tbl[dev->if_port].name); + vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait); + add_timer(&vp->timer); + } + outw((media_status & ~(Media_10TP|Media_SQE)) | + media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media); + + EL3WINDOW(3); + config.i = inl(ioaddr + Wn3_Config); + config.u.xcvr = dev->if_port; + outl(config.i, ioaddr + Wn3_Config); + + outw(dev->if_port == 3 ? StartCoax : StopCoax, ioaddr + EL3_CMD); + } + EL3WINDOW(old_window); + } restore_flags(flags); + if (vortex_debug > 1) + printk("%s: Media selection timer finished, %s.\n", + dev->name, media_tbl[dev->if_port].name); + +#endif /* AUTOMEDIA*/ + return; } static int @@ -638,33 +737,53 @@ struct vortex_private *vp = (struct vortex_private *)dev->priv; int ioaddr = dev->base_addr; - /* Transmitter timeout, serious problems. */ + /* Part of the following code is inspired by code from Giuseppe Ciaccio, + ciaccio@disi.unige.it. + It works around a ?bug? in the 8K Vortex that only occurs on some + systems: the TxAvailable interrupt seems to be lost. + The ugly work-around is to busy-wait for room available in the Tx + buffer before deciding the transmitter is actually hung. + This busy-wait should never really occur, since the problem is that + there actually *is* room in the Tx FIFO. + + This pointed out an optimization -- we can ignore dev->tbusy if + we actually have room for this packet. + */ + +#if 0 + /* unstable optimization */ + if (inw(ioaddr + TxFree) > skb->len) /* We actually have free room. */ + dev->tbusy = 0; /* Fake out the check below. */ + else +#endif if (dev->tbusy) { + /* Transmitter timeout, serious problems. */ int tickssofar = jiffies - dev->trans_start; - if (tickssofar < 40) + int i; + + if (tickssofar < 2) /* We probably aren't empty. */ return 1; - printk("%s: transmit timed out, tx_status %2.2x status %4.4x.\n", - dev->name, inb(ioaddr + TxStatus), inw(ioaddr + EL3_STATUS)); - vp->stats.tx_errors++; - /* Issue TX_RESET and TX_START commands. */ - outw(TxReset, ioaddr + EL3_CMD); - { - int i; + /* Wait a while to see if there really is room. */ + for (i = WAIT_TX_AVAIL; i >= 0; i--) + if (inw(ioaddr + TxFree) > skb->len) + break; + if ( i < 0) { + if (tickssofar < TX_TIMEOUT) + return 1; + printk("%s: transmit timed out, tx_status %2.2x status %4.4x.\n", + dev->name, inb(ioaddr + TxStatus), inw(ioaddr + EL3_STATUS)); + /* Issue TX_RESET and TX_START commands. */ + outw(TxReset, ioaddr + EL3_CMD); for (i = 20; i >= 0 ; i--) - if ( ! inw(ioaddr + EL3_STATUS) & CmdInProgress) - break; + if ( ! inw(ioaddr + EL3_STATUS) & CmdInProgress) break; + outw(TxEnable, ioaddr + EL3_CMD); + dev->trans_start = jiffies; + dev->tbusy = 0; + vp->stats.tx_errors++; + vp->stats.tx_dropped++; + return 0; /* Yes, silently *drop* the packet! */ } - outw(TxEnable, ioaddr + EL3_CMD); - dev->trans_start = jiffies; dev->tbusy = 0; - return 0; - } - - if (skb == NULL || skb->len <= 0) { - printk("%s: Obsolete driver layer request made: skbuff==NULL.\n", - dev->name); - dev_tint(dev); - return 0; } /* Block a timer-based transmit from overlapping. This could better be @@ -684,6 +803,7 @@ outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen); vp->tx_skb = skb; outw(StartDMADown, ioaddr + EL3_CMD); + /* dev->tbusy will be cleared at the DMADone interrupt. */ } else { /* ... and the packet rounded to a doubleword. */ outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); @@ -736,23 +856,15 @@ /* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */ -static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static void vortex_interrupt IRQ(int irq, void *dev_id, struct pt_regs *regs) { -#ifdef USE_SHARED_IRQ - struct device *dev = (struct device *)(irq == 0 ? regs : irq2dev_map[irq]); -#else - struct device *dev = (struct device *)(irq2dev_map[irq]); -#endif + /* Use the now-standard shared IRQ implementation. */ + struct device *dev = dev_id; struct vortex_private *lp; int ioaddr, status; int latency; int i = 0; - if (dev == NULL) { - printk ("vortex_interrupt(): irq %d for unknown device.\n", irq); - return; - } - if (dev->interrupt) printk("%s: Re-entering the interrupt handler.\n", dev->name); dev->interrupt = 1; @@ -774,7 +886,7 @@ if (donedidthis++ > 1) { printk("%s: Bogus interrupt, bailing. Status %4.4x, start=%d.\n", dev->name, status, dev->start); - free_irq(dev->irq, NULL); + FREE_IRQ(dev->irq, dev); } } @@ -833,10 +945,7 @@ /* Adapter failure requires Rx reset and reinit. */ outw(RxReset, ioaddr + EL3_CMD); /* Set the Rx filter to the current state. */ - outw(SetRxFilter | RxStation | RxBroadcast - | (dev->flags & IFF_ALLMULTI ? RxMulticast : 0) - | (dev->flags & IFF_PROMISC ? RxProm : 0), - ioaddr + EL3_CMD); + set_rx_mode(dev); outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */ outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD); } @@ -890,7 +999,7 @@ short pkt_len = rx_status & 0x1fff; struct sk_buff *skb; - skb = dev_alloc_skb(pkt_len + 5); + skb = DEV_ALLOC_SKB(pkt_len + 5); if (vortex_debug > 4) printk("Receiving packet size %d status %4.4x.\n", pkt_len, rx_status); @@ -927,6 +1036,7 @@ static int vortex_close(struct device *dev) { + struct vortex_private *vp = (struct vortex_private *)dev->priv; int ioaddr = dev->base_addr; dev->start = 0; @@ -936,6 +1046,8 @@ printk("%s: vortex_close() status %4.4x, Tx status %2.2x.\n", dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TxStatus)); + del_timer(&vp->timer); + /* Turn off statistics ASAP. We update lp->stats below. */ outw(StatsDisable, ioaddr + EL3_CMD); @@ -946,24 +1058,11 @@ if (dev->if_port == 3) /* Turn off thinnet power. Green! */ outw(StopCoax, ioaddr + EL3_CMD); - else if (dev->if_port == 0) { - /* Disable link beat and jabber, if_port may change ere next open(). */ - EL3WINDOW(4); - outw(inw(ioaddr + Wn4_Media) & ~Media_TP, ioaddr + Wn4_Media); - } -#ifdef USE_SHARED_IRQ - free_shared_irq(dev->irq, dev); -#else - free_irq(dev->irq, NULL); - /* Mmmm, we should disable all interrupt sources here. */ - irq2dev_map[dev->irq] = 0; -#endif + FREE_IRQ(dev->irq, dev); update_stats(ioaddr, dev); -#ifdef MODULE MOD_DEC_USE_COUNT; -#endif return 0; } @@ -1019,26 +1118,27 @@ return; } -/* There are two version of set_multicast_list() to support both v1.2 and - v1.4 kernels. */ +/* This new version of set_rx_mode() supports v1.4 kernels. + The Vortex chip has no documented multicast filter, so the only + multicast setting is to receive all multicast frames. At least + the chip has a very clean way to set the mode, unlike many others. */ static void -set_multicast_list(struct device *dev) +set_rx_mode(struct device *dev) { short ioaddr = dev->base_addr; + short new_mode; - if ((dev->mc_list) || (dev->flags & IFF_ALLMULTI)) { - outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD); - if (vortex_debug > 3) { - printk("%s: Setting Rx multicast mode, %d addresses.\n", - dev->name, dev->mc_count); - } - } else if (dev->flags & IFF_PROMISC) { - outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm, - ioaddr + EL3_CMD); - } else - outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD); -} + if (dev->flags & IFF_PROMISC) { + if (vortex_debug > 3) + printk("%s: Setting promiscuous mode.\n", dev->name); + new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast|RxProm; + } else if ((dev->mc_list) || (dev->flags & IFF_ALLMULTI)) { + new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast; + } else + new_mode = SetRxFilter | RxStation | RxBroadcast; + outw(new_mode, ioaddr + EL3_CMD); +} #ifdef MODULE void @@ -1050,6 +1150,7 @@ while (root_vortex_dev) { next_dev = ((struct vortex_private *)root_vortex_dev->priv)->next_module; unregister_netdev(root_vortex_dev); + outw(TotalReset, root_vortex_dev->base_addr + EL3_CMD); release_region(root_vortex_dev->base_addr, VORTEX_TOTAL_SIZE); kfree(root_vortex_dev); root_vortex_dev = next_dev; @@ -1059,7 +1160,7 @@ /* * Local variables: - * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c 3c59x.c -o 3c59x.o" + * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c 3c59x.c -o ../../modules/3c59x.o" * c-indent-level: 4 * tab-width: 4 * End: diff -ur --new-file old/linux/drivers/net/arcnet.c new/linux/drivers/net/arcnet.c --- old/linux/drivers/net/arcnet.c Fri Jun 7 10:58:11 1996 +++ new/linux/drivers/net/arcnet.c Tue Aug 6 11:58:35 1996 @@ -17,6 +17,19 @@ ********************** + v2.55 (96/08/05) + - A couple more messages moved to D_EXTRA. + - SLOW_XMIT_COPY off by default. + - Some tiny changes. + + v2.54 (96/07/05) + - Under some situations, Stage 5 autoprobe was a little bit too + picky about the TXACK flag. + - D_EXTRA removed from default debugging flags. Hey, it's stable, + right? + - Removed redundant "unknown protocol ID" messages and made remaining + ones D_EXTRA. + v2.53 (96/06/06) - arc0e and arc0s wouldn't initialize in newer kernels, which don't like dev->open==NULL or dev->stop==NULL. @@ -146,14 +159,19 @@ TO DO: (semi-prioritized) - - Smarter recovery from RECON-during-transmit conditions. + - Support "arpless" mode like NetBSD does, and as recommended + by the (obsoleted) RFC1051. + - Smarter recovery from RECON-during-transmit conditions. (ie. + retransmit immediately) - Make arcnetE_send_packet use arcnet_prepare_tx for loading the packet into ARCnet memory. - - Probe for multiple devices in one shot (trying to decide whether - to do it the "ugly" way or not). - - Add support for the new 1.3.x IP header cache features. - - Debug level should be changed with a system call, not a hack to - the "metric" flag. + - Some cards have shared memory with 4k mirrors instead of just 2k, + so we (uneventfully) find the "wrong" shmem when probing. + - Probe for multiple devices in one shot (trying to decide whether + to do it the "ugly" way or not). + - Add support for the new 1.3.x IP header cache, and other features. + - Debug level should be changed with a system call, not a hack to + the "metric" flag. - What about cards with shared memory that can be "turned off?" (or that have none at all, like the SMC PC500longboard) - Autoconfigure PDI5xxPlus cards. (I now have a PDI508Plus to play @@ -184,7 +202,7 @@ */ static const char *version = - "arcnet.c: v2.53 96/06/06 Avery Pennarun \n"; + "arcnet.c: v2.55 96/08/05 Avery Pennarun \n"; @@ -236,11 +254,11 @@ * defines; ARCnet probably is not the only driver that can screw up an * ftape DMA transfer. * - * Turn this off if you don't have timing-sensitive DMA (ie. a tape drive) - * and would like the little bit of speed back. It's on by default because - * - trust me - it's very difficult to figure out that you need it! + * Turn this on if you have timing-sensitive DMA (ie. a tape drive) and + * would like to sacrifice a little bit of network speed to reduce tape + * write retries or some related problem. */ -#define SLOW_XMIT_COPY +#undef SLOW_XMIT_COPY /* The card sends the reconfiguration signal when it loses the connection to * the rest of its network. It is a 'Hello, is anybody there?' cry. This @@ -341,7 +359,7 @@ #endif #ifndef ARCNET_DEBUG -#define ARCNET_DEBUG (D_NORMAL|D_EXTRA) +#define ARCNET_DEBUG (D_NORMAL) #endif int arcnet_debug = ARCNET_DEBUG; @@ -976,7 +994,7 @@ ioaddr=*port; status=inb(STATUS); - if ((status & 0x9F) + if ((status & 0x9D) != (NORXflag|RECONflag|TXFREEflag|RESETflag)) { BUGMSG2(D_INIT_REASONS,"(status=%Xh)\n",status); @@ -2240,7 +2258,7 @@ #endif case ARC_P_LANSOFT: /* don't understand. fall through. */ default: - BUGMSG(D_NORMAL,"received unknown protocol %d (%Xh) from station %d.\n", + BUGMSG(D_EXTRA,"received unknown protocol %d (%Xh) from station %d.\n", arcsoft[0],arcsoft[0],saddr); lp->stats.rx_errors++; lp->stats.rx_crc_errors++; @@ -2302,7 +2320,7 @@ if (in->skb) /* already assembling one! */ { - BUGMSG(D_NORMAL,"aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n", + BUGMSG(D_EXTRA,"aborting assembly (seq=%d) for unsplit packet (splitflag=%d, seq=%d)\n", in->sequence,arcsoft->split_flag, arcsoft->sequence); kfree_skb(in->skb,FREE_WRITE); @@ -2399,7 +2417,7 @@ if (in->skb && in->sequence!=arcsoft->sequence) { - BUGMSG(D_NORMAL,"wrong seq number (saddr=%d, expected=%d, seq=%d, splitflag=%d)\n", + BUGMSG(D_EXTRA,"wrong seq number (saddr=%d, expected=%d, seq=%d, splitflag=%d)\n", saddr,in->sequence,arcsoft->sequence, arcsoft->split_flag); kfree_skb(in->skb,FREE_WRITE); @@ -2415,7 +2433,7 @@ arcsoft->split_flag); if (in->skb) /* already assembling one! */ { - BUGMSG(D_NORMAL,"aborting previous (seq=%d) assembly (splitflag=%d, seq=%d)\n", + BUGMSG(D_EXTRA,"aborting previous (seq=%d) assembly (splitflag=%d, seq=%d)\n", in->sequence,arcsoft->split_flag, arcsoft->sequence); lp->stats.rx_errors++; @@ -2429,7 +2447,7 @@ if (in->numpackets>16) { - BUGMSG(D_NORMAL,"incoming packet more than 16 segments; dropping. (splitflag=%d)\n", + BUGMSG(D_EXTRA,"incoming packet more than 16 segments; dropping. (splitflag=%d)\n", arcsoft->split_flag); lp->stats.rx_errors++; lp->stats.rx_length_errors++; @@ -2469,7 +2487,7 @@ */ if (!in->skb) { - BUGMSG(D_NORMAL,"can't continue split without starting first! (splitflag=%d, seq=%d)\n", + BUGMSG(D_EXTRA,"can't continue split without starting first! (splitflag=%d, seq=%d)\n", arcsoft->split_flag,arcsoft->sequence); lp->stats.rx_errors++; lp->stats.rx_missed_errors++; @@ -2482,7 +2500,7 @@ /* harmless duplicate? ignore. */ if (packetnum<=in->lastpacket-1) { - BUGMSG(D_NORMAL,"duplicate splitpacket ignored! (splitflag=%d)\n", + BUGMSG(D_EXTRA,"duplicate splitpacket ignored! (splitflag=%d)\n", arcsoft->split_flag); lp->stats.rx_errors++; lp->stats.rx_frame_errors++; @@ -2490,7 +2508,7 @@ } /* "bad" duplicate, kill reassembly */ - BUGMSG(D_NORMAL,"out-of-order splitpacket, reassembly (seq=%d) aborted (splitflag=%d, seq=%d)\n", + BUGMSG(D_EXTRA,"out-of-order splitpacket, reassembly (seq=%d) aborted (splitflag=%d, seq=%d)\n", in->sequence,arcsoft->split_flag, arcsoft->sequence); kfree_skb(in->skb,FREE_WRITE); @@ -2733,8 +2751,6 @@ case ARC_P_NOVELL_EC: return htons(ETH_P_802_3); default: - BUGMSG(D_NORMAL,"received packet of unknown protocol id %d (%Xh)\n", - head->protocol_id,head->protocol_id); lp->stats.rx_errors++; lp->stats.rx_crc_errors++; return 0; @@ -3196,8 +3212,6 @@ case ARC_P_ARP_RFC1051: return htons(ETH_P_ARP); case ARC_P_ATALK: return htons(ETH_P_ATALK); /* untested appletalk */ default: - BUGMSG(D_NORMAL,"received packet of unknown protocol id %d (%Xh)\n", - head->protocol_id,head->protocol_id); lp->stats.rx_errors++; lp->stats.rx_crc_errors++; return 0; diff -ur --new-file old/linux/drivers/net/bsd_comp.c new/linux/drivers/net/bsd_comp.c --- old/linux/drivers/net/bsd_comp.c Fri Apr 12 08:49:37 1996 +++ new/linux/drivers/net/bsd_comp.c Wed Jul 17 06:17:29 1996 @@ -58,7 +58,6 @@ #include -#include #include #include #include @@ -77,6 +76,7 @@ #include #include #include +#include #include @@ -141,11 +141,11 @@ union { /* hash value */ unsigned long fcode; struct { -#ifndef BIG_ENDIAN_BITFIELD /* Little endian order */ +#if defined(__LITTLE_ENDIAN) /* Little endian order */ unsigned short prefix; /* preceding code */ unsigned char suffix; /* last character of new code */ unsigned char pad; -#else /* Big endian order */ +#elif defined(__BIG_ENDIAN) /* Big endian order */ unsigned char pad; unsigned char suffix; /* last character of new code */ unsigned short prefix; /* preceding code */ diff -ur --new-file old/linux/drivers/net/de4x5.c new/linux/drivers/net/de4x5.c --- old/linux/drivers/net/de4x5.c Sat Jun 1 17:56:10 1996 +++ new/linux/drivers/net/de4x5.c Tue Aug 20 07:45:26 1996 @@ -1,4 +1,4 @@ -/* de4x5.c: A DIGITAL DE425/DE434/DE435/DE500 ethernet driver for Linux. +/* de4x5.c: A DIGITAL DE425/DE434/DE435/DE450/DE500 ethernet driver for Linux. Copyright 1994, 1995 Digital Equipment Corporation. @@ -191,15 +191,30 @@ Fix bug in dc21040 and dc21041 autosense code. Remove buffer copies on receive for Intels. Change sk_buff handling during media disconnects to - eliminate DUP packets. + eliminate DUP packets. Add dynamic TX thresholding. Change all chips to use perfect multicast filtering. Fix alloc_device() bug + 0.43 21-Jun-96 Fix unconnected media TX retry bug. + Add Accton to the list of broken cards. + Fix TX under-run bug for non DC21140 chips. + Fix boot command probe bug in alloc_device() as + reported by and + . + Add cache locks to prevent a race condition as + reported by and + . + Upgraded alloc_device() code. + 0.431 28-Jun-96 Fix potential bug in queue_pkt() from discussion + with + 0.44 13-Aug-96 Fix RX overflow bug in 2114[023] chips. + Fix EISA probe bugs reported by + and ========================================================================= */ -static const char *version = "de4x5.c:v0.42 96/4/26 davies@wanton.lkg.dec.com\n"; +static const char *version = "de4x5.c:v0.44 96/8/13 davies@wanton.lkg.dec.com\n"; #include @@ -226,6 +241,7 @@ #include #include #include +#include #include "de4x5.h" @@ -274,10 +290,12 @@ ** Define special SROM detection cases */ static c_char enet_det[][ETH_ALEN] = { - {0x00, 0x00, 0xc0, 0x00, 0x00, 0x00} + {0x00, 0x00, 0xc0, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0xe8, 0x00, 0x00, 0x00} }; -#define SMC 1 +#define SMC 1 +#define ACCTON 2 #ifdef DE4X5_DEBUG @@ -331,6 +349,7 @@ #define MAX_EISA_SLOTS 16 #define EISA_SLOT_INC 0x1000 +#define EISA_ALLOWED_IRQ_LIST {5, 9, 10, 11} #define DE4X5_SIGNATURE {"DE425","DE434","DE435","DE450","DE500"} #define DE4X5_NAME_LENGTH 8 @@ -511,6 +530,7 @@ struct { void *priv; /* Original kmalloc'd mem addr */ void *buf; /* Original kmalloc'd mem addr */ + int lock; /* Lock the cache accesses */ s32 csr0; /* Saved Bus Mode Register */ s32 csr6; /* Saved Operating Mode Reg. */ s32 csr7; /* Saved IRQ Mask Register */ @@ -520,6 +540,7 @@ int save_cnt; /* Flag if state already saved */ struct sk_buff *skb; /* Save the (re-ordered) skb's */ } cache; + int rx_ovf; /* Check for 'RX overflow' tag */ }; /* @@ -557,6 +578,7 @@ static void de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs); static int de4x5_close(struct device *dev); static struct enet_statistics *de4x5_get_stats(struct device *dev); +static void de4x5_local_stats(struct device *dev, char *buf, int pkt_len); static void set_multicast_list(struct device *dev); static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd); @@ -570,6 +592,7 @@ static int de4x5_tx(struct device *dev); static int de4x5_ast(struct device *dev); static int de4x5_txur(struct device *dev); +static int de4x5_rx_ovfc(struct device *dev); static int autoconf_media(struct device *dev); static void create_packet(struct device *dev, char *frame, int len); @@ -633,12 +656,15 @@ static void eisa_probe(struct device *dev, u_long iobase); static void pci_probe(struct device *dev, u_long iobase); static struct device *alloc_device(struct device *dev, u_long iobase); +static struct device *insert_device(struct device *dev, u_long iobase, + int (*init)(struct device *)); static char *build_setup_frame(struct device *dev, int mode); static void disable_ast(struct device *dev); static void enable_ast(struct device *dev, u32 time_out); static long de4x5_switch_to_srl(struct device *dev); static long de4x5_switch_to_mii(struct device *dev); static void timeout(struct device *dev, void (*fn)(u_long data), u_long data, u_long msec); +static int de4x5_dev_index(char *s); static void de4x5_dbg_open(struct device *dev); static void de4x5_dbg_mii(struct device *dev, int k); static void de4x5_dbg_media(struct device *dev); @@ -655,7 +681,9 @@ #endif /* MODULE */ static char name[DE4X5_NAME_LENGTH + 1]; +static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST; static int num_de4x5s = 0, num_eth = 0; +static int cfrv = 0; /* ** Miscellaneous defines... @@ -683,7 +711,7 @@ { int tmp = num_de4x5s, status = -ENODEV; u_long iobase = dev->base_addr; - + eisa_probe(dev, iobase); pci_probe(dev, iobase); @@ -691,7 +719,7 @@ printk("%s: de4x5_probe() cannot find device at 0x%04lx.\n", dev->name, iobase); } - + /* ** Walk the device list to check that at least one device ** initialised OK @@ -739,10 +767,10 @@ dev->base_addr = iobase; if (lp->bus == EISA) { - printk("%s: %s at %04lx (EISA slot %ld)", + printk("%s: %s at 0x%04lx (EISA slot %ld)", dev->name, name, iobase, ((iobase>>12)&0x0f)); } else { /* PCI port address */ - printk("%s: %s at %04lx (PCI bus %d, device %d)", dev->name, name, + printk("%s: %s at 0x%04lx (PCI bus %d, device %d)", dev->name, name, iobase, lp->bus_num, lp->device); } @@ -871,6 +899,12 @@ /* Create a loopback packet frame for later media probing */ create_packet(dev, lp->frame, sizeof(lp->frame)); + /* Check if the RX overflow bug needs testing for */ + tmpchs = cfrv & 0x000000fe; + if ((lp->chipset == DC21140) && (tmpchs == 0x20)) { + lp->rx_ovf = 1; + } + /* Initialise the adapter state */ lp->state = CLOSED; @@ -1076,6 +1110,7 @@ return 0; } + set_bit(0, (void*)&dev->tbusy); /* Stop send re-tries */ if (lp->tx_enable == NO) { /* Cannot send for now */ return -1; } @@ -1085,11 +1120,13 @@ ** interrupts are lost by delayed descriptor status updates relative to ** the irq assertion, especially with a busy PCI bus. */ - set_bit(0, (void*)&dev->tbusy); cli(); de4x5_tx(dev); sti(); - + + /* Test if cache is already locked - requeue skb if so */ + if (set_bit(0, (void *)&lp->cache.lock) && !dev->interrupt) return -1; + /* Transmit descriptor ring full or stale skb */ if (dev->tbusy || lp->tx_skb[lp->tx_new]) { if (dev->interrupt) { @@ -1108,28 +1145,25 @@ } while (skb && !dev->tbusy && !lp->tx_skb[lp->tx_new]) { - set_bit(0, (void*)&dev->tbusy); cli(); - if (TX_BUFFS_AVAIL) { /* Fill in a Tx ring entry */ - load_packet(dev, skb->data, - TD_IC | TD_LS | TD_FS | skb->len, skb); - outl(POLL_DEMAND, DE4X5_TPD);/* Start the TX */ + set_bit(0, (void*)&dev->tbusy); + load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb); + outl(POLL_DEMAND, DE4X5_TPD);/* Start the TX */ - lp->tx_new = (++lp->tx_new) % lp->txRingSize; - dev->trans_start = jiffies; + lp->tx_new = (++lp->tx_new) % lp->txRingSize; + dev->trans_start = jiffies; - if (TX_BUFFS_AVAIL) { - dev->tbusy = 0; /* Another pkt may be queued */ - } - skb = de4x5_get_cache(dev); + if (TX_BUFFS_AVAIL) { + dev->tbusy = 0; /* Another pkt may be queued */ } + skb = de4x5_get_cache(dev); sti(); } - if (skb && (dev->tbusy || lp->tx_skb[lp->tx_new])) { - de4x5_putb_cache(dev, skb); - } + if (skb) de4x5_putb_cache(dev, skb); } + lp->cache.lock = 0; + return status; } @@ -1195,8 +1229,11 @@ } /* Load the TX ring with any locally stored packets */ - while (lp->cache.skb && !dev->tbusy && lp->tx_enable) { - de4x5_queue_pkt(de4x5_get_cache(dev), dev); + if (!set_bit(0, (void *)&lp->cache.lock)) { + while (lp->cache.skb && !dev->tbusy && lp->tx_enable) { + de4x5_queue_pkt(de4x5_get_cache(dev), dev); + } + lp->cache.lock = 0; } dev->interrupt = UNMASK_INTERRUPTS; @@ -1209,13 +1246,20 @@ de4x5_rx(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - int i, entry; + u_long iobase = dev->base_addr; + int entry; s32 status; - char *buf; for (entry=lp->rx_new; lp->rx_ring[entry].status>=0;entry=lp->rx_new) { status = lp->rx_ring[entry].status; + if (lp->rx_ovf) { + if (inl(DE4X5_MFC) & MFC_FOCM) { + de4x5_rx_ovfc(dev); + break; + } + } + if (status & RD_FS) { /* Remember the start of frame */ lp->rx_old = entry; } @@ -1244,34 +1288,13 @@ } de4x5_dbg_rx(skb, pkt_len); - /* Push up the protocol stack */ + /* Push up the protocol stack */ skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); /* Update stats */ lp->stats.rx_packets++; - for (i=1; ipktStats.bins[i]++; - i = DE4X5_PKT_STAT_SZ; - } - } - buf = skb->data; /* Look at the dest addr */ - if (buf[0] & 0x01) { /* Multicast/Broadcast */ - if ((*(s32 *)&buf[0] == -1) && (*(s16 *)&buf[4] == -1)) { - lp->pktStats.broadcast++; - } else { - lp->pktStats.multicast++; - } - } else if ((*(s32 *)&buf[0] == *(s32 *)&dev->dev_addr[0]) && - (*(s16 *)&buf[4] == *(s16 *)&dev->dev_addr[4])) { - lp->pktStats.unicast++; - } - - lp->pktStats.bins[0]++; /* Duplicates stats.rx_packets */ - if (lp->pktStats.bins[0] == 0) { /* Reset counters */ - memset((char *)&lp->pktStats, 0, sizeof(lp->pktStats)); - } + de4x5_local_stats(dev, skb->data, pkt_len); } /* Change buffer ownership for this frame, back to the adapter */ @@ -1313,7 +1336,6 @@ if (status & TD_NC) lp->stats.tx_carrier_errors++; if (status & TD_LC) lp->stats.tx_window_errors++; if (status & TD_UF) lp->stats.tx_fifo_errors++; - if (status & TD_LC) lp->stats.collisions++; if (status & TD_EC) lp->pktStats.excessive_collisions++; if (status & TD_DE) lp->stats.tx_aborted_errors++; @@ -1328,6 +1350,10 @@ lp->lostMedia = 0; /* Remove transient problem */ lp->linkOK++; } + /* Update the collision counter */ + lp->stats.collisions += ((status & TD_EC) ? 16 : + ((status & TD_CC) >> 3)); + /* Free the buffer. */ if (lp->tx_skb[entry] != NULL) { dev_kfree_skb(lp->tx_skb[entry], FREE_WRITE); @@ -1376,7 +1402,7 @@ int omr; omr = inl(DE4X5_OMR); - if (!(omr & OMR_SF)) { + if (!(omr & OMR_SF) || (lp->chipset==DC21041) || (lp->chipset==DC21040)) { omr &= ~(OMR_ST|OMR_SR); outl(omr, DE4X5_OMR); while (inl(DE4X5_STS) & STS_TS); @@ -1391,6 +1417,27 @@ return 0; } +static int +de4x5_rx_ovfc(struct device *dev) +{ + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + int iobase = dev->base_addr; + int omr; + + omr = inl(DE4X5_OMR); + outl(omr & ~OMR_SR, DE4X5_OMR); + while (inl(DE4X5_STS) & STS_RS); + + for (; lp->rx_ring[lp->rx_new].status>=0;) { + lp->rx_ring[lp->rx_new].status = R_OWN; + lp->rx_new = (++lp->rx_new % lp->rxRingSize); + } + + outl(omr, DE4X5_OMR); + + return 0; +} + static int de4x5_close(struct device *dev) { @@ -1444,6 +1491,37 @@ } static void +de4x5_local_stats(struct device *dev, char *buf, int pkt_len) +{ + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + int i; + + for (i=1; ipktStats.bins[i]++; + i = DE4X5_PKT_STAT_SZ; + } + } + if (buf[0] & 0x01) { /* Multicast/Broadcast */ + if ((*(s32 *)&buf[0] == -1) && (*(s16 *)&buf[4] == -1)) { + lp->pktStats.broadcast++; + } else { + lp->pktStats.multicast++; + } + } else if ((*(s32 *)&buf[0] == *(s32 *)&dev->dev_addr[0]) && + (*(s16 *)&buf[4] == *(s16 *)&dev->dev_addr[4])) { + lp->pktStats.unicast++; + } + + lp->pktStats.bins[0]++; /* Duplicates stats.rx_packets */ + if (lp->pktStats.bins[0] == 0) { /* Reset counters */ + memset((char *)&lp->pktStats, 0, sizeof(lp->pktStats)); + } + + return; +} + +static void load_packet(struct device *dev, char *buf, u32 flags, struct sk_buff *skb) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; @@ -1564,6 +1642,7 @@ u_long iobase; struct bus_type *lp = &bus; char name[DE4X5_STRLEN]; + struct device *tmp; if (!ioaddr && autoprobed) return; /* Been here before ! */ @@ -1582,22 +1661,26 @@ for (status = -ENODEV; (i> 16); vendor = (u_short) cfid; + /* Read the EISA Configuration Registers */ + dev->irq = inb(EISA_REG0); + dev->irq = de4x5_irq[(dev->irq >> 1) & 0x03]; + lp->chipset = device; - DevicePresent(EISA_APROM); + DevicePresent(DE4X5_APROM); /* Write the PCI Configuration Registers */ outl(PCI_COMMAND_IO | PCI_COMMAND_MASTER, PCI_CFCS); - outl(0x00004000, PCI_CFLT); + outl(0x00006000, PCI_CFLT); outl(iobase, PCI_CBIO); if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE) == 0) { - if ((dev = alloc_device(dev, iobase)) != NULL) { - if ((status = de4x5_hw_init(dev, iobase)) == 0) { + if ((tmp = alloc_device(dev, iobase)) != NULL) { + if ((status = de4x5_hw_init(tmp, iobase)) == 0) { num_de4x5s++; } - num_eth++; } } else if (autoprobed) { printk("%s: region already allocated at 0x%04lx.\n", dev->name,iobase); @@ -1632,6 +1715,7 @@ u_int class = DE4X5_CLASS_CODE; u_int iobase; struct bus_type *lp = &bus; + struct device *tmp; if ((!ioaddr || !loading_module) && autoprobed) return; @@ -1639,14 +1723,14 @@ lp->bus = PCI; - if (ioaddr < 0x1000) { + if ((ioaddr < 0x1000) && loading_module) { pbus = (u_short)(ioaddr >> 8); dnum = (u_short)(ioaddr & 0xff); } else { pbus = 0; dnum = 0; } - + for (index=0; (pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND); index++) { @@ -1664,10 +1748,13 @@ /* Set the chipset information */ lp->chipset = device; + /* Get the chip configuration revision register */ + pcibios_read_config_dword(pb, PCI_DEVICE, PCI_REVISION_ID, &cfrv); + /* Get the board I/O address */ pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &iobase); iobase &= CBIO_MASK; - + /* Fetch the IRQ to be used */ pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, &irq); if ((irq == 0) || (irq == (u_char) 0xff)) continue; @@ -1684,12 +1771,11 @@ DevicePresent(DE4X5_APROM); if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) { - if ((dev = alloc_device(dev, iobase)) != NULL) { - dev->irq = irq; - if ((status = de4x5_hw_init(dev, iobase)) == 0) { + if ((tmp = alloc_device(dev, iobase)) != NULL) { + tmp->irq = irq; + if ((status = de4x5_hw_init(tmp, iobase)) == 0) { num_de4x5s++; } - num_eth++; } } else if (autoprobed) { printk("%s: region already allocated at 0x%04x.\n", dev->name, @@ -1702,109 +1788,95 @@ } /* -** Allocate the device by pointing to the next available space in the -** device structure. Should one not be available, it is created. +** Search the entire 'eth' device list for a fixed probe. If a match isn't +** found then check for an autoprobe or unused device location. If they +** are not available then insert a new device structure at the end of +** the current list. */ static struct device * alloc_device(struct device *dev, u_long iobase) { - int addAutoProbe = 0; - struct device *tmp = NULL, *ret; - int (*init)(struct device *) = NULL; - + struct device *adev = NULL; + int fixed = 0, new_dev = 0; + + num_eth = de4x5_dev_index(dev->name); if (loading_module) return dev; - /* - ** Check the device structures for an end of list or unused device - */ - while (dev->next != NULL) { - if ((dev->base_addr == DE4X5_NDA) || (dev->base_addr == 0)) break; - dev = dev->next; /* walk through eth device list */ - num_eth++; /* increment eth device number */ + while (1) { + if (((dev->base_addr == DE4X5_NDA) || (dev->base_addr==0)) && !adev) { + adev=dev; + } else if ((dev->priv == NULL) && (dev->base_addr==iobase)) { + fixed = 1; + } else { + if (dev->next == NULL) { + new_dev = 1; + } else if (strncmp(dev->next->name, "eth", 3) != 0) { + new_dev = 1; + } + } + if ((dev->next == NULL) || new_dev || fixed) break; + dev = dev->next; + num_eth++; } - - /* - ** If an autoprobe is requested for another device, we must re-insert - ** the request later in the list. Remember the current position first. - */ - if ((dev->base_addr == 0) && (num_de4x5s > 0)) { - addAutoProbe++; - tmp = dev->next; /* point to the next device */ - init = dev->init; /* remember the probe function */ + if (adev && !fixed) { + dev = adev; + num_eth = de4x5_dev_index(dev->name); + new_dev = 0; + } + + if (((dev->next == NULL) && + ((dev->base_addr != DE4X5_NDA) && (dev->base_addr != 0)) && !fixed) || + new_dev) { + num_eth++; /* New device */ + dev = insert_device(dev, iobase, de4x5_probe); } - /* - ** If at end of list and can't use current entry, malloc one up. - ** If memory could not be allocated, print an error message. - */ - if ((dev->next == NULL) && - !((dev->base_addr == DE4X5_NDA) || (dev->base_addr == 0))) { - dev->next = (struct device *)kmalloc(sizeof(struct device)+8, GFP_KERNEL); - dev = dev->next; /* point to the new device */ - if (dev == NULL) { - printk("eth%d: Device not initialised, insufficient memory\n", num_eth); + return dev; +} + +/* +** If at end of eth device list and can't use current entry, malloc +** one up. If memory could not be allocated, print an error message. +*/ +static struct device * +insert_device(struct device *dev, u_long iobase, int (*init)(struct device *)) +{ + struct device *new; + + new = (struct device *)kmalloc(sizeof(struct device)+8, GFP_KERNEL); + if (new == NULL) { + printk("eth%d: Device not initialised, insufficient memory\n",num_eth); + return NULL; + } else { + new->next = dev->next; + dev->next = new; + dev = dev->next; /* point to the new device */ + dev->name = (char *)(dev + 1); + if (num_eth > 9999) { + sprintf(dev->name,"eth????");/* New device name */ } else { - /* - ** If the memory was allocated, point to the new memory area - ** and initialize it (name, I/O address, next device (NULL) and - ** initialisation probe routine). - */ - dev->name = (char *)(dev + 1); - if (num_eth > 9999) { - sprintf(dev->name,"eth????");/* New device name */ - } else { - sprintf(dev->name,"eth%d", num_eth);/* New device name */ - } - dev->base_addr = iobase; /* assign the io address */ - dev->next = NULL; /* mark the end of list */ - dev->init = &de4x5_probe; /* initialisation routine */ - num_de4x5s++; + sprintf(dev->name,"eth%d", num_eth);/* New device name */ } + dev->base_addr = iobase; /* assign the io address */ + dev->init = init; /* initialisation routine */ } - ret = dev; /* return current struct, or NULL */ - - /* - ** Now figure out what to do with the autoprobe that has to be inserted. - ** Firstly, search the (possibly altered) list for an empty space. - */ - if (ret != NULL) { - if (addAutoProbe) { - for (; (tmp->next!=NULL) && (tmp->base_addr!=DE4X5_NDA); tmp=tmp->next); - /* - ** If no more device structures and can't use the current one, - ** malloc one up. If memory could not be allocated, print an error - **message. - */ - if ((tmp->next == NULL) && !(tmp->base_addr == DE4X5_NDA)) { - tmp->next = (struct device *)kmalloc(sizeof(struct device) + 8, - GFP_KERNEL); - tmp = tmp->next; /* point to the new device */ - if (tmp == NULL) { - printk("%s: Insufficient memory to extend the device list.\n", - dev->name); - } else { - /* - ** If the memory was allocated, point to the new memory - ** area and initialize it (name, I/O address, next device - ** (NULL) and initialisation probe routine). - */ - tmp->name = (char *)(tmp + 1); - if (num_eth > 9999) { - sprintf(tmp->name,"eth????"); - } else { /* New device name */ - sprintf(tmp->name,"eth%d", num_eth); - } - tmp->base_addr = 0; /* re-insert the io address */ - tmp->next = NULL; /* mark the end of list */ - tmp->init = init; /* initialisation routine */ - } - } else { /* structure already exists */ - tmp->base_addr = 0; /* re-insert the io address */ - } - } + + return dev; +} + +static int +de4x5_dev_index(char *s) +{ + int i=0, j=0; + + for (;*s; s++) { + if (isdigit(*s)) { + j=1; + i = (i * 10) + (*s - '0'); + } else if (j) break; } - - return ret; + + return i; } /* @@ -1907,12 +1979,8 @@ break; case NC: -#ifndef __alpha__ + /* default to TP for all */ reset_init_sia(dev, 0x8f01, 0xffff, 0x0000); -#else - /* JAE: for Alpha, default to BNC/AUI, *not* TP */ - reset_init_sia(dev, 0x8f09, 0x0705, 0x0006); -#endif /* i386 */ if (lp->media != lp->c_media) { de4x5_dbg_media(dev); lp->c_media = lp->media; @@ -2381,8 +2449,10 @@ de4x5_setup_intr(dev); lp->lostMedia = 0; lp->tx_enable = YES; + dev->tbusy = 0; sti(); outl(POLL_DEMAND, DE4X5_TPD); + mark_bh(NET_BH); return; } @@ -2643,8 +2713,9 @@ ret = lp->rx_skb[index]; lp->rx_skb[index] = p; - if ((unsigned long) ret > 1) - skb_put(ret, len); + if ((u_long) ret > 1) { + skb_put(ret, len); + } return ret; @@ -2675,7 +2746,7 @@ int i; for (i=0; irxRingSize; i++) { - if ((unsigned long) lp->rx_skb[i] > 1) { + if ((u_long) lp->rx_skb[i] > 1) { dev_kfree_skb(lp->rx_skb[i], FREE_WRITE); } lp->rx_ring[i].status = 0; @@ -2728,7 +2799,6 @@ de4x5_cache_state(dev, DE4X5_SAVE_STATE); de4x5_sw_reset(dev); de4x5_cache_state(dev, DE4X5_RESTORE_STATE); - dev->tbusy = 0; lp->cache.save_cnt++; START_DE4X5; } @@ -2748,7 +2818,6 @@ de4x5_cache_state(dev, DE4X5_SAVE_STATE); de4x5_sw_reset(dev); de4x5_cache_state(dev, DE4X5_RESTORE_STATE); - dev->tbusy = 0; lp->cache.save_cnt--; START_DE4X5; } @@ -3074,7 +3143,7 @@ } else if (!broken) { dev->dev_addr[i] = (u_char) lp->srom.ieee_addr[i]; i++; dev->dev_addr[i] = (u_char) lp->srom.ieee_addr[i]; i++; - } else if (broken == SMC) { /* Assume SMC9332 for now */ + } else if ((broken == SMC) || (broken == ACCTON)) { dev->dev_addr[i] = *((u_char *)&lp->srom + i); i++; dev->dev_addr[i] = *((u_char *)&lp->srom + i); i++; } @@ -3118,7 +3187,11 @@ for (i=0; isrom, (char *)&enet_det[i], 3) && !de4x5_strncmp((char *)&lp->srom+0x10, (char *)&enet_det[i], 3)) { - status = SMC; + if (i == 0) { + status = SMC; + } else if (i == 1) { + status = ACCTON; + } break; } } @@ -3540,7 +3613,10 @@ /* Restore CSR6 */ outl(omr, DE4X5_OMR); - + + /* Reset CSR8 */ + inl(DE4X5_MFC); + return omr; } @@ -3567,6 +3643,9 @@ /* Restore CSR6 */ outl(omr, DE4X5_OMR); + /* Reset CSR8 */ + inl(DE4X5_MFC); + return omr; } @@ -4123,8 +4202,8 @@ /* * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O2 -m486 -c de4x5.c" + * compile-command: "gcc -D__KERNEL__ -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c de4x5.c" * - * compile-command: "gcc -D__KERNEL__ -DMODULE -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O2 -m486 -c de4x5.c" + * compile-command: "gcc -D__KERNEL__ -DMODULE -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c de4x5.c" * End: */ diff -ur --new-file old/linux/drivers/net/de4x5.h new/linux/drivers/net/de4x5.h --- old/linux/drivers/net/de4x5.h Sat Apr 27 10:14:49 1996 +++ new/linux/drivers/net/de4x5.h Tue Aug 20 07:45:26 1996 @@ -337,10 +337,19 @@ #define IMR_TIM 0x00000001 /* Transmit Interrupt Mask */ /* -** DC21040 Missed Frame Counter (DE4X5_MFC) +** DC21040 Missed Frames Counter (DE4X5_MFC) */ -#define MFC_OVFL 0x00010000 /* Counter Overflow Bit */ -#define MFC_CNTR 0x0000ffff /* Counter Bits */ +#define MFC_OVFL 0x00010000 /* Missed Frames Counter Overflow Bit */ +#define MFC_CNTR 0x0000ffff /* Missed Frames Counter Bits */ + +/* +** DC21140 Missed Frames and FIFO Overflow Counters (DE4X5_MFC) +*/ +#define MFC_FOCO 0x10000000 /* FIFO Overflow Counter Overflow Bit */ +#define MFC_FOC 0x0ffe0000 /* FIFO Overflow Counter Bits */ +#define MFC_OVFL 0x00010000 /* Missed Frames Counter Overflow Bit */ +#define MFC_CNTR 0x0000ffff /* Missed Frames Counter Bits */ +#define MFC_FOCM 0x1ffe0000 /* FIFO Overflow Counter Mask */ /* ** DC21040 Ethernet Address PROM (DE4X5_APROM) diff -ur --new-file old/linux/drivers/net/depca.c new/linux/drivers/net/depca.c --- old/linux/drivers/net/depca.c Mon Apr 29 16:11:39 1996 +++ new/linux/drivers/net/depca.c Tue Aug 20 07:45:26 1996 @@ -202,11 +202,13 @@ Add new multicasting code. 0.421 22-Apr-96 Fix alloc_device() bug 0.422 29-Apr-96 Fix depca_hw_init() bug + 0.423 7-Jun-96 Fix module load bug + 0.43 16-Aug-96 Update alloc_device() to conform to de4x5.c ========================================================================= */ -static const char *version = "depca.c:v0.422 96/4/29 davies@wanton.lkg.dec.com\n"; +static const char *version = "depca.c:v0.43 96/8/16 davies@wanton.lkg.dec.com\n"; #include @@ -231,6 +233,7 @@ #include #include #include +#include #include "depca.h" @@ -407,6 +410,8 @@ static void isa_probe(struct device *dev, u_long iobase); static void eisa_probe(struct device *dev, u_long iobase); static struct device *alloc_device(struct device *dev, u_long iobase); +static int depca_dev_index(char *s); +static struct device *insert_device(struct device *dev, u_long iobase, int (*init)(struct device *)); static int load_packet(struct device *dev, struct sk_buff *skb); static void depca_dbg_open(struct device *dev); @@ -483,22 +488,13 @@ outb(nicsr, DEPCA_NICSR); if (inw(DEPCA_DATA) == STOP) { - if (mem == 0) { - while (mem_base[mem_chkd]) { - mem_start = mem_base[mem_chkd++]; - DepcaSignature(name, mem_start); - if (*name != '\0') break; - } - } else { - mem_start = mem; - if (adapter_name) { - strcpy(name, adapter_name); - } else{ - DepcaSignature(name, mem_start); - } - } + do { + strcpy(name, (adapter_name ? adapter_name : "")); + mem_start = (mem ? mem & 0xf0000 : mem_base[mem_chkd++]); + DepcaSignature(name, mem_start); + } while (!mem && mem_base[mem_chkd] && (adapter == unknown)); - if ((*name != '\0') && mem_start) { /* found a DEPCA device */ + if ((adapter != unknown) && mem_start) { /* found a DEPCA device */ dev->base_addr = ioaddr; if ((ioaddr&0x0fff)==DEPCA_EISA_IO_PORTS) {/* EISA slot address */ @@ -650,6 +646,8 @@ printk(" which has an Ethernet PROM CRC error.\n"); status = -ENXIO; } + } else { + status = -ENXIO; } if (!status) { if (depca_debug > 0) { @@ -1290,113 +1288,95 @@ } /* -** Allocate the device by pointing to the next available space in the -** device structure. Should one not be available, it is created. +** Search the entire 'eth' device list for a fixed probe. If a match isn't +** found then check for an autoprobe or unused device location. If they +** are not available then insert a new device structure at the end of +** the current list. */ -static struct device *alloc_device(struct device *dev, u_long iobase) +static struct device * +alloc_device(struct device *dev, u_long iobase) { - int addAutoProbe = 0; - struct device *tmp = NULL, *ret; - int (*init)(struct device *) = NULL; + struct device *adev = NULL; + int fixed = 0, new_dev = 0; - /* - ** Check the device structures for an end of list or unused device - */ - if (!loading_module) { - while (dev->next != NULL) { - if ((dev->base_addr == DEPCA_NDA) || (dev->base_addr == 0)) break; - dev = dev->next; /* walk through eth device list */ - num_eth++; /* increment eth device number */ + num_eth = depca_dev_index(dev->name); + if (loading_module) return dev; + + while (1) { + if (((dev->base_addr == DEPCA_NDA) || (dev->base_addr==0)) && !adev) { + adev=dev; + } else if ((dev->priv == NULL) && (dev->base_addr==iobase)) { + fixed = 1; + } else { + if (dev->next == NULL) { + new_dev = 1; + } else if (strncmp(dev->next->name, "eth", 3) != 0) { + new_dev = 1; + } + } + if ((dev->next == NULL) || new_dev || fixed) break; + dev = dev->next; + num_eth++; + } + if (adev && !fixed) { + dev = adev; + num_eth = depca_dev_index(dev->name); + new_dev = 0; } - /* - ** If an autoprobe is requested for another device, we must re-insert - ** the request later in the list. Remember the current information. - */ - if ((dev->base_addr == 0) && (num_depcas > 0)) { - addAutoProbe++; - tmp = dev->next; /* point to the next device */ - init = dev->init; /* remember the probe function */ + if (((dev->next == NULL) && + ((dev->base_addr != DEPCA_NDA) && (dev->base_addr != 0)) && !fixed) || + new_dev) { + num_eth++; /* New device */ + dev = insert_device(dev, iobase, depca_probe); } + + return dev; +} - /* - ** If at end of list and can't use current entry, malloc one up. - ** If memory could not be allocated, print an error message. - */ - if ((dev->next == NULL) && - !((dev->base_addr == DEPCA_NDA) || (dev->base_addr == 0))){ - dev->next = (struct device *)kmalloc(sizeof(struct device) + 8, - GFP_KERNEL); - - dev = dev->next; /* point to the new device */ - if (dev == NULL) { - printk("eth%d: Device not initialised, insufficient memory\n", - num_eth); - } else { - /* - ** If the memory was allocated, point to the new memory area - ** and initialize it (name, I/O address, next device (NULL) and - ** initialisation probe routine). - */ +/* +** If at end of eth device list and can't use current entry, malloc +** one up. If memory could not be allocated, print an error message. +*/ +static struct device * +insert_device(struct device *dev, u_long iobase, int (*init)(struct device *)) +{ + struct device *new; + + new = (struct device *)kmalloc(sizeof(struct device)+8, GFP_KERNEL); + if (new == NULL) { + printk("eth%d: Device not initialised, insufficient memory\n",num_eth); + return NULL; + } else { + new->next = dev->next; + dev->next = new; + dev = dev->next; /* point to the new device */ dev->name = (char *)(dev + 1); if (num_eth > 9999) { - sprintf(dev->name,"eth????"); /* New device name */ + sprintf(dev->name,"eth????");/* New device name */ } else { - sprintf(dev->name,"eth%d", num_eth);/* New device name */ + sprintf(dev->name,"eth%d", num_eth);/* New device name */ } - dev->base_addr = iobase; /* assign the io address */ - dev->next = NULL; /* mark the end of list */ - dev->init = &depca_probe; /* initialisation routine */ - num_depcas++; - } + dev->base_addr = iobase; /* assign the io address */ + dev->init = init; /* initialisation routine */ } - ret = dev; /* return current struct, or NULL */ - - /* - ** Now figure out what to do with the autoprobe that has to be inserted. - ** Firstly, search the (possibly altered) list for an empty space. - */ - if (ret != NULL) { - if (addAutoProbe) { - for (;(tmp->next!=NULL) && (tmp->base_addr!=DEPCA_NDA); tmp=tmp->next); - - /* - ** If no more device structures and can't use the current one, malloc - ** one up. If memory could not be allocated, print an error message. - */ - if ((tmp->next == NULL) && !(tmp->base_addr == DEPCA_NDA)) { - tmp->next = (struct device *)kmalloc(sizeof(struct device) + 8, - GFP_KERNEL); - tmp = tmp->next; /* point to the new device */ - if (tmp == NULL) { - printk("%s: Insufficient memory to extend the device list.\n", - dev->name); - } else { - /* - ** If the memory was allocated, point to the new memory area - ** and initialize it (name, I/O address, next device (NULL) and - ** initialisation probe routine). - */ - tmp->name = (char *)(tmp + 1); - if (num_eth > 9999) { - sprintf(tmp->name,"eth????"); /* New device name */ - } else { - sprintf(tmp->name,"eth%d", num_eth);/* New device name */ - } - tmp->base_addr = 0; /* re-insert the io address */ - tmp->next = NULL; /* mark the end of list */ - tmp->init = init; /* initialisation routine */ - } - } else { /* structure already exists */ - tmp->base_addr = 0; /* re-insert the io address */ - } - } + + return dev; +} + +static int +depca_dev_index(char *s) +{ + int i=0, j=0; + + for (;*s; s++) { + if (isdigit(*s)) { + j=1; + i = (i * 10) + (*s - '0'); + } else if (j) break; } - } else { - ret = dev; - } - return ret; + return i; } /* @@ -1410,12 +1390,13 @@ const char *signatures[] = DEPCA_SIGNATURE; char tmpstr[16]; - for (i=0;i<16;i++) { /* copy the first 16 bytes of ROM to */ - tmpstr[i] = readb(paddr+0xc000+i); /* a temporary string */ + /* Copy the first 16 bytes of ROM */ + for (i=0;i<16;i++) { + tmpstr[i] = readb(paddr+0xc000+i); } - strcpy(name,""); - for (i=0;*signatures[i]!='\0' && *name=='\0';i++) { + /* Check if PROM contains a valid string */ + for (i=0;*signatures[i]!='\0';i++) { for (j=0,k=0;j<16 && k @@ -110,7 +114,7 @@ /* use 0 for production, 1 for verification, >2 for debug */ #ifndef NET_DEBUG -#define NET_DEBUG 2 +#define NET_DEBUG 3 #endif static unsigned int net_debug = NET_DEBUG; @@ -180,15 +184,26 @@ network traffics, the ring linked list should improve performance by allowing up to 8K worth of packets to be queued. +The sizes of the receive and transmit buffers can now be changed via lilo +or insmod. Lilo uses the appended line "ether=io,irq,debug,rx-buffer,eth0" +where rx-buffer is in KB unit. Modules uses the parameter mem which is +also in KB unit, for example "insmod io=io-address irq=0 mem=rx-buffer." +The receive buffer has to be more than 3K or less than 29K. Otherwise, +it is reset to the default of 24K, and, hence, 8K for the trasnmit +buffer (transmit-buffer = 32K - receive-buffer). + */ #define RAM_SIZE 0x8000 #define RCV_HEADER 8 -#define RCV_RAM 0x6000 /* 24KB for RCV buffer */ -#define RCV_LOWER_LIMIT 0x00 /* 0x0000 */ -#define RCV_UPPER_LIMIT ((RCV_RAM - 2) >> 8) /* 0x5ffe */ -#define XMT_RAM (RAM_SIZE - RCV_RAM) /* 8KB for XMT buffer */ -#define XMT_LOWER_LIMIT (RCV_RAM >> 8) /* 0x6000 */ -#define XMT_UPPER_LIMIT ((RAM_SIZE - 2) >> 8) /* 0x7ffe */ +#define RCV_RAM 0x6000 /* 24KB default for RCV buffer */ +#define RCV_LOWER_LIMIT 0x00 /* 0x0000 */ +/* #define RCV_UPPER_LIMIT ((RCV_RAM - 2) >> 8) */ /* 0x5ffe */ +#define RCV_UPPER_LIMIT (((rcv_ram) - 2) >> 8) +/* #define XMT_RAM (RAM_SIZE - RCV_RAM) */ /* 8KB for XMT buffer */ +#define XMT_RAM (RAM_SIZE - (rcv_ram)) /* 8KB for XMT buffer */ +/* #define XMT_LOWER_LIMIT (RCV_RAM >> 8) */ /* 0x6000 */ +#define XMT_LOWER_LIMIT ((rcv_ram) >> 8) +#define XMT_UPPER_LIMIT ((RAM_SIZE - 2) >> 8) /* 0x7ffe */ #define XMT_HEADER 8 #define RCV_DONE 0x0008 @@ -368,6 +383,16 @@ dev->dev_addr[i] = ((unsigned char *) station_addr)[5-i]; printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]); } + + if ((dev->mem_end & 0x3f) < 3 || /* RX buffer must be more than 3K */ + (dev->mem_end & 0x3f) > 29) /* and less than 29K */ + dev->mem_end = RCV_RAM; /* or it will be set to 24K */ + else dev->mem_end = 1024*dev->mem_end; /* Maybe I should shift << 10 */ + + /* From now on, dev->mem_end contains the actual size of rx buffer */ + + if (net_debug > 3) + printk(", %dK RCV buffer", (int)(dev->mem_end)/1024); outb(BANK2_SELECT, ioaddr); /* be CAREFUL, BANK 2 now */ id = inb(ioaddr + REG3); @@ -401,8 +426,8 @@ } else printk(", %s.\n", ifmap[dev->if_port]); - if ((dev->mem_start & 0xf) > 0) - net_debug = dev->mem_start & 7; + if ((dev->mem_start & 0xf) > 0) /* I don't know if this is */ + net_debug = dev->mem_start & 7; /* still useful or not */ if (net_debug > 3) { i = read_eeprom(ioaddr, 5); @@ -516,7 +541,7 @@ eepro_open(struct device *dev) { unsigned short temp_reg, old8, old9; - int i, ioaddr = dev->base_addr; + int i, ioaddr = dev->base_addr, rcv_ram = dev->mem_end; struct eepro_local *lp = (struct eepro_local *)dev->priv; if (net_debug > 3) @@ -654,6 +679,7 @@ { struct eepro_local *lp = (struct eepro_local *)dev->priv; int ioaddr = dev->base_addr; + int rcv_ram = dev->mem_end; if (net_debug > 5) printk("eepro: entering eepro_send_packet routine.\n"); @@ -662,12 +688,13 @@ /* If we get here, some higher level has decided we are broken. There should really be a "kick me" function call instead. */ int tickssofar = jiffies - dev->trans_start; - if (tickssofar < 5) + if (tickssofar < 40) return 1; if (net_debug > 1) printk("%s: transmit timed out, %s?\n", dev->name, "network cable problem"); lp->stats.tx_errors++; + /* Try to restart the adaptor. */ outb(SEL_RESET_CMD, ioaddr); /* We are supposed to wait for 2 us after a SEL_RESET */ @@ -675,7 +702,7 @@ SLOW_DOWN_IO; /* Do I also need to flush the transmit buffers here? YES? */ - lp->tx_start = lp->tx_end = RCV_RAM; + lp->tx_start = lp->tx_end = rcv_ram; lp->tx_last = 0; dev->tbusy=0; @@ -722,7 +749,7 @@ eepro_interrupt(int irq, void *dev_id, struct pt_regs * regs) { struct device *dev = (struct device *)(irq2dev_map[irq]); - int ioaddr, status, boguscount = 0; + int ioaddr, status, boguscount = 20; if (net_debug > 5) printk("eepro: entering eepro_interrupt routine.\n"); @@ -737,7 +764,7 @@ do { status = inb(ioaddr + STATUS_REG); - + if (status & RX_INT) { if (net_debug > 4) printk("eepro: packet received interrupt.\n"); @@ -748,6 +775,7 @@ /* Get the received packets */ eepro_rx(dev); } + else if (status & TX_INT) { if (net_debug > 4) printk("eepro: packet transmit interrupt.\n"); @@ -757,10 +785,9 @@ /* Process the status of transmitted packets */ eepro_transmit_interrupt(dev); - dev->tbusy = 0; - mark_bh(NET_BH); - } - } while ((++boguscount < 10) && (status & 0x06)); + } + + } while ((boguscount-- > 0) && (status & 0x06)); dev->interrupt = 0; if (net_debug > 5) @@ -774,6 +801,7 @@ { struct eepro_local *lp = (struct eepro_local *)dev->priv; int ioaddr = dev->base_addr; + int rcv_ram = dev->mem_end; short temp_reg; dev->tbusy = 1; @@ -789,7 +817,7 @@ /* Flush the Tx and disable Rx. */ outb(STOP_RCV_CMD, ioaddr); - lp->tx_start = lp->tx_end = RCV_RAM ; + lp->tx_start = lp->tx_end = rcv_ram ; lp->tx_last = 0; /* Mask all the interrupts. */ @@ -912,7 +940,9 @@ outw(status | CHAIN_BIT, ioaddr + IO_PORT); lp->tx_end = i ; } - else lp->tx_start = lp->tx_end = i ; + else { + lp->tx_start = lp->tx_end = i ; + } /* Acknowledge that the MC setup is done */ do { /* We should be doing this in the eepro_interrupt()! */ @@ -993,13 +1023,25 @@ { struct eepro_local *lp = (struct eepro_local *)dev->priv; short ioaddr = dev->base_addr; - unsigned status, tx_available, last, end, boguscount = 10; + int rcv_ram = dev->mem_end; + unsigned status, tx_available, last, end, boguscount = 100; if (net_debug > 5) printk("eepro: entering hardware_send_packet routine.\n"); while (boguscount-- > 0) { + /* Disable RX and TX interrupts. Necessary to avoid + corruption of the HOST_ADDRESS_REG by interrupt + service routines. */ + outb(ALL_MASK, ioaddr + INT_MASK_REG); + + if (dev->interrupt == 1) { + /* Enable RX and TX interrupts */ + outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); + continue; + } + /* determine how much of the transmit buffer space is available */ if (lp->tx_end > lp->tx_start) tx_available = XMT_RAM - (lp->tx_end - lp->tx_start); @@ -1007,14 +1049,15 @@ tx_available = lp->tx_start - lp->tx_end; else tx_available = XMT_RAM; - /* Disable RX and TX interrupts. Necessary to avoid - corruption of the HOST_ADDRESS_REG by interrupt - service routines. */ - outb(ALL_MASK, ioaddr + INT_MASK_REG); - if (((((length + 3) >> 1) << 1) + 2*XMT_HEADER) >= tx_available) /* No space available ??? */ + { + eepro_transmit_interrupt(dev); /* Clean up the transmiting queue */ + + /* Enable RX and TX interrupts */ + outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); continue; + } last = lp->tx_end; end = last + (((length + 3) >> 1) << 1) + XMT_HEADER; @@ -1023,10 +1066,10 @@ if ((RAM_SIZE - last) <= XMT_HEADER) { /* Arrrr!!!, must keep the xmt header together, several days were lost to chase this one down. */ - last = RCV_RAM; + last = rcv_ram; end = last + (((length + 3) >> 1) << 1) + XMT_HEADER; } - else end = RCV_RAM + (end - RAM_SIZE); + else end = rcv_ram + (end - RAM_SIZE); } outw(last, ioaddr + HOST_ADDRESS_REG); @@ -1044,9 +1087,17 @@ outb(temp & ~(IO_32_BIT), ioaddr + INT_MASK_REG); } - if (lp->tx_start != lp->tx_end) { + /* A dummy read to flush the DRAM write pipeline */ + status = inw(ioaddr + IO_PORT); + + if (lp->tx_start == lp->tx_end) { + outw(last, ioaddr + XMT_BAR); + outb(XMT_CMD, ioaddr); + lp->tx_start = last; /* I don't like to change tx_start here */ + } + else { /* update the next address and the chain bit in the - last packet */ + last packet */ if (lp->tx_end != last) { outw(lp->tx_last + XMT_CHAIN, ioaddr + HOST_ADDRESS_REG); outw(last, ioaddr + IO_PORT); @@ -1054,33 +1105,26 @@ outw(lp->tx_last + XMT_COUNT, ioaddr + HOST_ADDRESS_REG); status = inw(ioaddr + IO_PORT); outw(status | CHAIN_BIT, ioaddr + IO_PORT); - } - /* A dummy read to flush the DRAM write pipeline */ - status = inw(ioaddr + IO_PORT); - - /* Enable RX and TX interrupts */ - outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); - - if (lp->tx_start == lp->tx_end) { - outw(last, ioaddr + XMT_BAR); - outb(XMT_CMD, ioaddr); - lp->tx_start = last; /* I don't like to change tx_start here */ + /* Continue the transmit command */ + outb(RESUME_XMT_CMD, ioaddr); } - else outb(RESUME_XMT_CMD, ioaddr); lp->tx_last = last; lp->tx_end = end; + /* Enable RX and TX interrupts */ + outb(ALL_MASK & ~(RX_MASK | TX_MASK), ioaddr + INT_MASK_REG); + if (dev->tbusy) { dev->tbusy = 0; - mark_bh(NET_BH); } if (net_debug > 5) printk("eepro: exiting hardware_send_packet routine.\n"); return; } + dev->tbusy = 1; if (net_debug > 5) printk("eepro: exiting hardware_send_packet routine.\n"); @@ -1090,7 +1134,7 @@ eepro_rx(struct device *dev) { struct eepro_local *lp = (struct eepro_local *)dev->priv; - short ioaddr = dev->base_addr; + short ioaddr = dev->base_addr, rcv_ram = dev->mem_end; short boguscount = 20; short rcv_car = lp->rx_start; unsigned rcv_event, rcv_status, rcv_next_frame, rcv_size; @@ -1171,7 +1215,7 @@ { struct eepro_local *lp = (struct eepro_local *)dev->priv; short ioaddr = dev->base_addr; - short boguscount = 10; + short boguscount = 20; short xmt_status; while (lp->tx_start != lp->tx_end) { @@ -1179,16 +1223,15 @@ outw(lp->tx_start, ioaddr + HOST_ADDRESS_REG); xmt_status = inw(ioaddr+IO_PORT); if ((xmt_status & TX_DONE_BIT) == 0) break; + xmt_status = inw(ioaddr+IO_PORT); lp->tx_start = inw(ioaddr+IO_PORT); - - if (dev->tbusy) { - dev->tbusy = 0; - mark_bh(NET_BH); - } + + dev->tbusy = 0; + mark_bh(NET_BH); if (xmt_status & 0x2000) - lp->stats.tx_packets++; + lp->stats.tx_packets++; else { lp->stats.tx_errors++; if (xmt_status & 0x0400) @@ -1196,10 +1239,12 @@ printk("%s: XMT status = %#x\n", dev->name, xmt_status); } - if (xmt_status & 0x000f) + if (xmt_status & 0x000f) { lp->stats.collisions += (xmt_status & 0x000f); - if ((xmt_status & 0x0040) == 0x0) + } + if ((xmt_status & 0x0040) == 0x0) { lp->stats.tx_heartbeat_errors++; + } if (--boguscount == 0) break; @@ -1216,6 +1261,7 @@ static int io = 0x200; static int irq = 0; +static int mem = (RCV_RAM/1024); /* Size of the rx buffer in KB */ int init_module(void) @@ -1224,6 +1270,7 @@ printk("eepro: You should not use auto-probing with insmod!\n"); dev_eepro.base_addr = io; dev_eepro.irq = irq; + dev_eepro.mem_end = mem; if (register_netdev(&dev_eepro) != 0) return -EIO; diff -ur --new-file old/linux/drivers/net/ewrk3.c new/linux/drivers/net/ewrk3.c --- old/linux/drivers/net/ewrk3.c Tue Apr 23 08:22:01 1996 +++ new/linux/drivers/net/ewrk3.c Tue Aug 20 07:45:26 1996 @@ -127,17 +127,18 @@ 0.40 27-Dec-95 Rationalise MODULE and autoprobe code. Rewrite for portability & updated. ALPHA support from - Added verify_area() calls in depca_ioctl() from + Added verify_area() calls in ewrk3_ioctl() from suggestion by . Add new multicasting code. 0.41 20-Jan-96 Fix IRQ set up problem reported by . 0.42 22-Apr-96 Fix alloc_device() bug + 0.43 16-Aug-96 Update alloc_device() to conform to de4x5.c ========================================================================= */ -static const char *version = "ewrk3.c:v0.42 96/4/22 davies@wanton.lkg.dec.com\n"; +static const char *version = "ewrk3.c:v0.43 96/8/16 davies@wanton.lkg.dec.com\n"; #include @@ -162,6 +163,7 @@ #include #include #include +#include #include "ewrk3.h" @@ -315,6 +317,8 @@ static void isa_probe(struct device *dev, u_long iobase); static void eisa_probe(struct device *dev, u_long iobase); static struct device *alloc_device(struct device *dev, u_long iobase); +static int ewrk3_dev_index(char *s); +static struct device *insert_device(struct device *dev, u_long iobase, int (*init)(struct device *)); #ifdef MODULE @@ -1368,113 +1372,95 @@ } /* -** Allocate the device by pointing to the next available space in the -** device structure. Should one not be available, it is created. +** Search the entire 'eth' device list for a fixed probe. If a match isn't +** found then check for an autoprobe or unused device location. If they +** are not available then insert a new device structure at the end of +** the current list. */ -static struct device *alloc_device(struct device *dev, u_long iobase) +static struct device * +alloc_device(struct device *dev, u_long iobase) { - int addAutoProbe = 0; - struct device *tmp = NULL, *ret; - int (*init)(struct device *) = NULL; + struct device *adev = NULL; + int fixed = 0, new_dev = 0; - /* - ** Check the device structures for an end of list or unused device - */ - if (!loading_module) { - while (dev->next != NULL) { - if ((dev->base_addr == EWRK3_NDA) || (dev->base_addr == 0)) break; - dev = dev->next; /* walk through eth device list */ - num_eth++; /* increment eth device number */ + num_eth = ewrk3_dev_index(dev->name); + if (loading_module) return dev; + + while (1) { + if (((dev->base_addr == EWRK3_NDA) || (dev->base_addr==0)) && !adev) { + adev=dev; + } else if ((dev->priv == NULL) && (dev->base_addr==iobase)) { + fixed = 1; + } else { + if (dev->next == NULL) { + new_dev = 1; + } else if (strncmp(dev->next->name, "eth", 3) != 0) { + new_dev = 1; + } + } + if ((dev->next == NULL) || new_dev || fixed) break; + dev = dev->next; + num_eth++; + } + if (adev && !fixed) { + dev = adev; + num_eth = ewrk3_dev_index(dev->name); + new_dev = 0; } - /* - ** If an autoprobe is requested for another device, we must re-insert - ** the request later in the list. Remember the current position first. - */ - if ((dev->base_addr == 0) && (num_ewrk3s > 0)) { - addAutoProbe++; - tmp = dev->next; /* point to the next device */ - init = dev->init; /* remember the probe function */ + if (((dev->next == NULL) && + ((dev->base_addr != EWRK3_NDA) && (dev->base_addr != 0)) && !fixed) || + new_dev) { + num_eth++; /* New device */ + dev = insert_device(dev, iobase, ewrk3_probe); } + + return dev; +} - /* - ** If at end of list and can't use current entry, malloc one up. - ** If memory could not be allocated, print an error message. - */ - if ((dev->next == NULL) && - !((dev->base_addr == EWRK3_NDA) || (dev->base_addr == 0))){ - dev->next = (struct device *)kmalloc(sizeof(struct device) + 8, - GFP_KERNEL); - - dev = dev->next; /* point to the new device */ - if (dev == NULL) { - printk("eth%d: Device not initialised, insufficient memory\n", - num_eth); - } else { - /* - ** If the memory was allocated, point to the new memory area - ** and initialize it (name, I/O address, next device (NULL) and - ** initialisation probe routine). - */ +/* +** If at end of eth device list and can't use current entry, malloc +** one up. If memory could not be allocated, print an error message. +*/ +static struct device * +insert_device(struct device *dev, u_long iobase, int (*init)(struct device *)) +{ + struct device *new; + + new = (struct device *)kmalloc(sizeof(struct device)+8, GFP_KERNEL); + if (new == NULL) { + printk("eth%d: Device not initialised, insufficient memory\n",num_eth); + return NULL; + } else { + new->next = dev->next; + dev->next = new; + dev = dev->next; /* point to the new device */ dev->name = (char *)(dev + 1); if (num_eth > 9999) { - sprintf(dev->name,"eth????"); /* New device name */ + sprintf(dev->name,"eth????");/* New device name */ } else { - sprintf(dev->name,"eth%d", num_eth);/* New device name */ + sprintf(dev->name,"eth%d", num_eth);/* New device name */ } - dev->base_addr = iobase; /* assign the io address */ - dev->next = NULL; /* mark the end of list */ - dev->init = &ewrk3_probe; /* initialisation routine */ - num_ewrk3s++; - } + dev->base_addr = iobase; /* assign the io address */ + dev->init = init; /* initialisation routine */ } - ret = dev; /* return current struct, or NULL */ - - /* - ** Now figure out what to do with the autoprobe that has to be inserted. - ** Firstly, search the (possibly altered) list for an empty space. - */ - if (ret != NULL) { - if (addAutoProbe) { - for (;(tmp->next!=NULL) && (tmp->base_addr!=EWRK3_NDA); tmp=tmp->next); - /* - ** If no more device structures and can't use the current one, malloc - ** one up. If memory could not be allocated, print an error message. - */ - if ((tmp->next == NULL) && !(tmp->base_addr == EWRK3_NDA)) { - tmp->next = (struct device *)kmalloc(sizeof(struct device) + 8, - GFP_KERNEL); - tmp = tmp->next; /* point to the new device */ - if (tmp == NULL) { - printk("%s: Insufficient memory to extend the device list.\n", - dev->name); - } else { - /* - ** If the memory was allocated, point to the new memory area - ** and initialize it (name, I/O address, next device (NULL) and - ** initialisation probe routine). - */ - tmp->name = (char *)(tmp + 1); - if (num_eth > 9999) { - sprintf(tmp->name,"eth????"); /* New device name */ - } else { - sprintf(tmp->name,"eth%d", num_eth);/* New device name */ - } - tmp->base_addr = 0; /* re-insert the io address */ - tmp->next = NULL; /* mark the end of list */ - tmp->init = init; /* initialisation routine */ - } - } else { /* structure already exists */ - tmp->base_addr = 0; /* re-insert the io address */ - } - } + return dev; +} + +static int +ewrk3_dev_index(char *s) +{ + int i=0, j=0; + + for (;*s; s++) { + if (isdigit(*s)) { + j=1; + i = (i * 10) + (*s - '0'); + } else if (j) break; } - } else { - ret = dev; - } - return ret; + return i; } /* @@ -1927,9 +1913,9 @@ /* * Local variables: - * kernel-compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O2 -m486 -c ewrk3.c" + * compile-command: "gcc -D__KERNEL__ -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c ewrk3.c" * - * module-compile-command: "gcc -D__KERNEL__ -DMODULE -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O2 -m486 -c ewrk3.c" + * compile-command: "gcc -D__KERNEL__ -DMODULE -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c ewrk3.c" * End: */ diff -ur --new-file old/linux/drivers/net/lance32.c new/linux/drivers/net/lance32.c --- old/linux/drivers/net/lance32.c Tue May 7 11:06:50 1996 +++ new/linux/drivers/net/lance32.c Thu Jul 4 07:52:04 1996 @@ -789,8 +789,8 @@ lance32_get_stats(struct device *dev) { struct lance32_private *lp = (struct lance32_private *)dev->priv; - short ioaddr = dev->base_addr; - short saved_addr; + int ioaddr = dev->base_addr; + unsigned short saved_addr; unsigned long flags; save_flags(flags); @@ -809,7 +809,7 @@ static void lance32_set_multicast_list(struct device *dev) { - short ioaddr = dev->base_addr; + int ioaddr = dev->base_addr; struct lance32_private *lp = (struct lance32_private *)dev->priv; if (dev->flags&IFF_PROMISC) { diff -ur --new-file old/linux/drivers/net/net_init.c new/linux/drivers/net/net_init.c --- old/linux/drivers/net/net_init.c Thu Aug 29 16:32:46 1996 +++ new/linux/drivers/net/net_init.c Thu Aug 29 16:33:32 1996 @@ -20,6 +20,8 @@ Use dev_close cleanly so we always shut things down tidily. Changed 29/10/95, Alan Cox to pass sockaddr's around for mac addresses. + + 14/06/96 - Paul Gortmaker: Add generic eth_change_mtu() function. */ #include @@ -144,6 +146,14 @@ return 0; } +static int eth_change_mtu(struct device *dev, int new_mtu) +{ + if ((new_mtu < 68) || (new_mtu > 1500)) + return -EINVAL; + dev->mtu = new_mtu; + return 0; +} + void ether_setup(struct device *dev) { int i; @@ -165,6 +175,7 @@ } } + dev->change_mtu = eth_change_mtu; dev->hard_header = eth_header; dev->rebuild_header = eth_rebuild_header; dev->set_mac_address = eth_mac_addr; diff -ur --new-file old/linux/drivers/net/new_tunnel.c new/linux/drivers/net/new_tunnel.c --- old/linux/drivers/net/new_tunnel.c Mon Jun 3 11:42:41 1996 +++ new/linux/drivers/net/new_tunnel.c Fri Jul 19 07:24:05 1996 @@ -233,8 +233,9 @@ printk("Room left at tail: %d\n", skb_tailroom(skb)); printk("Required room: %d, Tunnel hlen: %d\n", max_headroom, TUNL_HLEN); #endif - if (skb_headroom(skb) >= max_headroom) { + if (skb_headroom(skb) >= max_headroom && skb->free) { skb->h.iph = (struct iphdr *) skb_push(skb, tunnel_hlen); + skb_device_unlock(skb); } else { struct sk_buff *new_skb; @@ -289,7 +290,7 @@ iph->tot_len = htons(skb->len); iph->id = htons(ip_id_count++); /* Race condition here? */ ip_send_check(iph); - skb->ip_hdr = skb->h.iph; + skb->ip_hdr = skb->h.iph; skb->protocol = htons(ETH_P_IP); #ifdef TUNNEL_DEBUG printk("New IP Header....\n"); @@ -303,7 +304,7 @@ */ #ifdef CONFIG_IP_FORWARD - if (ip_forward(skb, dev, 0, target)) + if (ip_forward(skb, dev, IPFWD_NOTTLDEC, target)) #endif kfree_skb(skb, FREE_WRITE); diff -ur --new-file old/linux/drivers/net/plip.c new/linux/drivers/net/plip.c --- old/linux/drivers/net/plip.c Sun May 19 13:57:51 1996 +++ new/linux/drivers/net/plip.c Fri Aug 9 12:33:52 1996 @@ -873,9 +873,9 @@ return 0; } - for (i=0; i < ETH_ALEN - sizeof(unsigned long); i++) + for (i=0; i < ETH_ALEN - sizeof(u32); i++) eth->h_dest[i] = 0xfc; - memcpy(&(eth->h_dest[i]), &dst, sizeof(unsigned long)); + *(u32 *)(eth->h_dest+i) = dst; return 0; } @@ -964,9 +964,9 @@ nl->is_deferred = 0; /* Fill in the MAC-level header. */ - for (i=0; i < ETH_ALEN - sizeof(unsigned long); i++) + for (i=0; i < ETH_ALEN - sizeof(u32); i++) dev->dev_addr[i] = 0xfc; - memcpy(&(dev->dev_addr[i]), &dev->pa_addr, sizeof(unsigned long)); + *(u32 *)(dev->dev_addr+i) = dev->pa_addr; dev->interrupt = 0; dev->start = 1; diff -ur --new-file old/linux/drivers/net/ppp.c new/linux/drivers/net/ppp.c --- old/linux/drivers/net/ppp.c Thu Aug 29 16:32:46 1996 +++ new/linux/drivers/net/ppp.c Thu Aug 29 16:33:32 1996 @@ -60,7 +60,6 @@ */ #include -#include #include #include #include @@ -399,7 +398,7 @@ dev->stop = ppp_dev_close; dev->get_stats = ppp_dev_stats; dev->do_ioctl = ppp_dev_ioctl; - dev->ip_arp = ether_arp; + dev->ip_arp = NULL; dev->addr_len = 0; dev->tx_queue_len = 10; dev->type = ARPHRD_PPP; diff -ur --new-file old/linux/drivers/net/slhc.c new/linux/drivers/net/slhc.c --- old/linux/drivers/net/slhc.c Sun May 19 12:29:22 1996 +++ new/linux/drivers/net/slhc.c Tue Jun 25 11:03:29 1996 @@ -107,29 +107,27 @@ memset(comp, 0, sizeof(struct slcompress)); if ( rslots > 0 && rslots < 256 ) { - comp->rstate = - (struct cstate *)kmalloc(rslots * sizeof(struct cstate), - GFP_KERNEL); + size_t rsize = rslots * sizeof(struct cstate); + comp->rstate = (struct cstate *) kmalloc(rsize, GFP_KERNEL); if (! comp->rstate) { kfree((unsigned char *)comp); return NULL; } - memset(comp->rstate, 0, rslots * sizeof(struct cstate)); + memset(comp->rstate, 0, rsize); comp->rslot_limit = rslots - 1; } if ( tslots > 0 && tslots < 256 ) { - comp->tstate = - (struct cstate *)kmalloc(tslots * sizeof(struct cstate), - GFP_KERNEL); + size_t tsize = tslots * sizeof(struct cstate); + comp->tstate = (struct cstate *) kmalloc(tsize, GFP_KERNEL); if (! comp->tstate) { kfree((unsigned char *)comp->rstate); kfree((unsigned char *)comp); return NULL; } - memset(comp->tstate, 0, tslots * sizeof(struct cstate)); + memset(comp->tstate, 0, tsize); comp->tslot_limit = tslots - 1; } diff -ur --new-file old/linux/drivers/net/strip.c new/linux/drivers/net/strip.c --- old/linux/drivers/net/strip.c Fri Apr 12 08:49:39 1996 +++ new/linux/drivers/net/strip.c Wed Aug 14 09:21:03 1996 @@ -14,33 +14,82 @@ * for kernel-based devices like TTY. It interfaces between a * raw TTY, and the kernel's INET protocol layers (via DDI). * - * Version: @(#)strip.c 0.9.1 3/6/95 + * Version: @(#)strip.c 0.9.8 June 1996 * * Author: Stuart Cheshire * - * Fixes: - * Stuart Cheshire: - * Original version converted from SLIP driver - * Jonathan Stone: - * change to 1.3 calling conventions - * Stuart Cheshire: - * v0.9 12th Feb 1996. - * New byte stuffing (2+6 run-length encoding) - * New watchdog timer task - * New Protocol key (SIP0) - * v0.9.1 3rd March 1996 - * Changed to dynamic device allocation + * Fixes: v0.9 12th Feb 1996. + * New byte stuffing (2+6 run-length encoding) + * New watchdog timer task + * New Protocol key (SIP0) + * + * v0.9.1 3rd March 1996 + * Changed to dynamic device allocation -- no more compile + * time (or boot time) limit on the number of STRIP devices. + * + * v0.9.2 13th March 1996 + * Uses arp cache lookups (but doesn't send arp packets yet) + * + * v0.9.3 17th April 1996 + * Fixed bug where STR_ERROR flag was getting set unneccessarily + * + * v0.9.4 27th April 1996 + * First attempt at using "&COMMAND" Starmode AT commands + * + * v0.9.5 29th May 1996 + * First attempt at sending (unicast) ARP packets + * + * v0.9.6 5th June 1996 + * Elliot put "message level" tags in every "printk" statement + * + * v0.9.7 13th June 1996 + * Added support for the /proc fs (laik) + * + * v0.9.8 July 1996 + * Added packet logging (Mema) + */ + +/* + * Undefine this symbol if you don't have PROC_NET_STRIP_STATUS + * defined in include/linux/proc_fs.h + */ + +#define DO_PROC_NET_STRIP_STATUS 1 + +/* + * Define this symbol if you want to enable STRIP packet tracing. */ +#define DO_PROC_NET_STRIP_TRACE 0 + + +/************************************************************************/ +/* Header files */ + #include + #ifdef MODULE #include #include #endif +#include #include #include #include + +/* + * isdigit() and isspace() use the ctype[] array, which is not available + * to kernel modules. If compiling as a module, use a local definition + * of isdigit() and isspace() until _ctype is added to ksyms. + */ +#ifdef MODULE +# define isdigit(c) ('0' <= (c) && (c) <= '9') +# define isspace(c) ((c) == ' ' || (c) == '\t') +#else +# include +#endif + #include #include #include @@ -52,82 +101,316 @@ #include #include #include +#include #include + #ifdef CONFIG_INET #include #include +#include #endif -#ifdef MODULE -#define STRIP_VERSION "0.9.1-STUART.CHESHIRE-MODULAR" -#else -#define STRIP_VERSION "0.9.1-STUART.CHESHIRE" -#endif -#define STRIP_MTU 1024 -#define STRIP_MAGIC 0x5303 +/************************************************************************/ +/* Useful structures and definitions */ /* - * Do we still needs all these flags? + * A MetricomKey identifies the protocol being carried inside a Metricom + * Starmode packet. */ -enum +typedef union { - STR_INUSE = 0, /* Channel in use */ - STR_ESCAPE, /* ESC received */ - STR_ERROR /* Parity, etc. error */ -} -STRIP_FLAGS; + __u8 c[4]; + __u32 l; +} MetricomKey; + +/* + * An IP address can be viewed as four bytes in memory (which is what it is) or as + * a single 32-bit long (which is convenient for assignment, equality testing etc.) + */ -struct strip +typedef union { - int magic; - /* - * Other useful structures. - */ + __u8 b[4]; + __u32 l; +} IPaddr; - /* - * These are pointers to the malloc()ed frame buffers. - */ +/* + * A MetricomAddressString is used to hold a printable representation of + * a Metricom address. + */ - unsigned char *rx_buff; /* buffer for received IP packet*/ - unsigned char *sx_buff; /* buffer for received serial data*/ - int sx_count; /* received serial data counter */ - unsigned char *tx_buff; /* transmitter buffer */ - unsigned char *tx_head; /* pointer to next byte to XMIT */ - int tx_left; /* bytes left in XMIT queue */ +typedef struct +{ + __u8 c[24]; +} MetricomAddressString; - /* - * STRIP interface statistics. - */ - - unsigned long rx_packets; /* inbound frames counter */ - unsigned long tx_packets; /* outbound frames counter */ - unsigned long rx_errors; /* Parity, etc. errors */ - unsigned long tx_errors; /* Planned stuff */ - unsigned long rx_dropped; /* No memory for skb */ - unsigned long tx_dropped; /* When MTU change */ - unsigned long rx_over_errors; /* Frame bigger then STRIP buf. */ +/* + * Note: A Metricom packet looks like this: *
* + * eg. *0000-1234*SIP0 + * A STRIP_Header is never really sent over the radio, but making a dummy header + * for internal use within the kernel that looks like an Ethernet header makes + * certain other software happier. For example, tcpdump already understands + * Ethernet headers. + */ - /* - * Internal variables. - */ - - struct strip *next; /* The next struct in the list */ - struct strip **referrer; /* The pointer that points to us */ - unsigned char flags; /* Flag values/ mode etc */ - int mtu; /* Our mtu (to spot changes!) */ - int buffsize; /* Max buffers sizes */ - long watchdog_doprobe; /* Next time to test the radio */ - long watchdog_doreset; /* Time to do next reset */ - struct timer_list idle_timer; - - struct tty_struct *tty; /* ptr to TTY structure */ - char if_name[8]; /* Dynamically generated name */ - struct device dev; /* Our device structure */ +typedef struct +{ + MetricomAddress dst_addr; /* Destination address, e.g. "0000-1234" */ + MetricomAddress src_addr; /* Source address, e.g. "0000-5678" */ + unsigned short protocol; /* The protocol type, using Ethernet codes */ +} STRIP_Header; + +typedef struct GeographicLocation +{ + char s[18]; +} GeographicLocation; + +typedef enum { + NodeValid = 0x1, + NodeHasWAN = 0x2, + NodeIsRouter = 0x4 +} NodeType; + +typedef struct MetricomNode +{ + NodeType type; /* Some flags about the type of node */ + GeographicLocation gl; /* The location of the node. */ + MetricomAddress addr; /* The metricom address of this node */ + int poll_latency; /* The latency to poll that node ? */ + int rssi; /* The Receiver Signal Strength Indicator */ + struct MetricomNode *next; /* The next node */ +} MetricomNode; + +enum { FALSE = 0, TRUE = 1 }; + +/* + * Holds the packet signature for an IP packet. + */ +typedef struct +{ + IPaddr src; + /* Data is stored in the following field in network byte order. */ + __u16 id; +} IPSignature; + +/* + * Holds the packet signature for an ARP packet. + */ +typedef struct +{ + IPaddr src; + /* Data is stored in the following field in network byte order. */ + __u16 op; +} ARPSignature; + +/* + * Holds the signature of a packet. + */ +typedef union +{ + IPSignature ip_sig; + ARPSignature arp_sig; + __u8 print_sig[6]; +} PacketSignature; + +typedef enum { + EntrySend = 0, + EntryReceive = 1 +} LogEntry; + +/* Structure for Packet Logging */ +typedef struct stripLog +{ + LogEntry entry_type; + u_long seqNum; + int packet_type; + PacketSignature sig; + MetricomAddress src; + MetricomAddress dest; + struct timeval timeStamp; + u_long rawSize; + u_long stripSize; + u_long slipSize; + u_long valid; +} StripLog; + +#define ENTRY_TYPE_TO_STRING(X) ((X) ? "r" : "s") + +#define BOOLEAN_TO_STRING(X) ((X) ? "true" : "false") + +/* + * Holds the radio's firmware version. + */ +typedef struct +{ + char c[50]; +} MetricomFirmwareVersion; + +/* + * Holds the radio's serial number. + */ +typedef struct +{ + char c[18]; +} MetricomSerialNumber; + +/* + * Holds the radio's battery voltage. + */ +typedef struct +{ + char c[11]; +} MetricomBatteryVoltage; + +struct strip +{ + int magic; + /* + * These are pointers to the malloc()ed frame buffers. + */ + + unsigned char *rx_buff; /* buffer for received IP packet*/ + unsigned char *sx_buff; /* buffer for received serial data*/ + int sx_count; /* received serial data counter */ + int sx_size; /* Serial buffer size */ + unsigned char *tx_buff; /* transmitter buffer */ + unsigned char *tx_head; /* pointer to next byte to XMIT */ + int tx_left; /* bytes left in XMIT queue */ + int tx_size; /* Serial buffer size */ + + /* + * STRIP interface statistics. + */ + + unsigned long rx_packets; /* inbound frames counter */ + unsigned long tx_packets; /* outbound frames counter */ + unsigned long rx_errors; /* Parity, etc. errors */ + unsigned long tx_errors; /* Planned stuff */ + unsigned long rx_dropped; /* No memory for skb */ + unsigned long tx_dropped; /* When MTU change */ + unsigned long rx_over_errors; /* Frame bigger then STRIP buf. */ + + /* + * Internal variables. + */ + + struct strip *next; /* The next struct in the list */ + struct strip **referrer; /* The pointer that points to us*/ + int discard; /* Set if serial error */ + int working; /* Is radio working correctly? */ + int structured_messages; /* Parsable AT response msgs? */ + int mtu; /* Our mtu (to spot changes!) */ + long watchdog_doprobe; /* Next time to test the radio */ + long watchdog_doreset; /* Time to do next reset */ + long gratuitous_arp; /* Time to send next ARP refresh*/ + long arp_interval; /* Next ARP interval */ + struct timer_list idle_timer; /* For periodic wakeup calls */ + MetricomNode *neighbor_list; /* The list of neighbor nodes */ + int neighbor_list_locked; /* Indicates the list is locked */ + MetricomFirmwareVersion firmware_version; /* The radio's firmware version */ + MetricomSerialNumber serial_number; /* The radio's serial number */ + MetricomBatteryVoltage battery_voltage; /* The radio's battery voltage */ + + /* + * Other useful structures. + */ + + struct tty_struct *tty; /* ptr to TTY structure */ + char if_name[8]; /* Dynamically generated name */ + struct device dev; /* Our device structure */ + + /* + * Packet Logging Structures. + */ + + u_long num_sent; + u_long num_received; + + int next_entry; /* The index of the oldest packet; */ + /* Also the next to be logged. */ + StripLog packetLog[610]; }; + + +/************************************************************************/ +/* Constants */ + +#ifdef MODULE +static const char StripVersion[] = "0.9.8-STUART.CHESHIRE-MODULAR"; +#else +static const char StripVersion[] = "0.9.8-STUART.CHESHIRE"; +#endif + +static const char TickleString1[] = "***&COMMAND*ATS305?\r"; +static const char TickleString2[] = "***&COMMAND*ATS305?\r\r" + "*&COMMAND*ATS300?\r\r*&COMMAND*ATS325?\r\r*&COMMAND*AT~I2 nn\r\r"; + +static const char hextable[16] = "0123456789ABCDEF"; + +static const MetricomAddress zero_address; +static const MetricomAddress broadcast_address = { { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF } }; + +static const MetricomKey SIP0Key = { { "SIP0" } }; +static const MetricomKey ARP0Key = { { "ARP0" } }; +static const MetricomKey ERR_Key = { { "ERR_" } }; +static const MetricomKey ATR_Key = { { "ATR " } }; + +static const long MaxARPInterval = 60 * HZ; /* One minute */ + +/* + * Maximum Starmode packet length (including starmode address) is 1183 bytes. + * Allowing 32 bytes for header, and 65/64 expansion for STRIP encoding, + * that translates to a maximum payload MTU of 1132. + */ +static const unsigned short MAX_STRIP_MTU = 1132; +static const unsigned short DEFAULT_STRIP_MTU = 1024; +static const int STRIP_MAGIC = 0x5303; +static const long LongTime = 0x7FFFFFFF; + +static const int STRIP_NODE_LEN = 64; +static const char STRIP_PORTABLE_CHAR = 'P'; +static const char STRIP_ROUTER_CHAR = 'r'; +static const int STRIP_PROC_BUFFER_SIZE = 4096; +static const int STRIP_LOG_INT_SIZE = 10; + /************************************************************************/ -/* Utility routines for disabling and restoring interrupts */ +/* Global variables */ + +static struct strip *struct_strip_list = NULL; + + +/************************************************************************/ +/* Macros */ + +#define READHEX(X) ((X)>='0' && (X)<='9' ? (X)-'0' : \ + (X)>='a' && (X)<='f' ? (X)-'a'+10 : \ + (X)>='A' && (X)<='F' ? (X)-'A'+10 : 0 ) + +#define READDEC(X) ((X)>='0' && (X)<='9' ? (X)-'0' : 0) + +#define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) +#define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) +#define ELEMENTS_OF(X) (sizeof(X) / sizeof((X)[0])) +#define ARRAY_END(X) (&((X)[ELEMENTS_OF(X)])) + +/* Encapsulation can expand packet of size x to 65/64x + 1 */ +/* Sent packet looks like "*
*" */ +/* 1 1-18 1 4 ? 1 */ +/* We allow 31 bytes for the stars, the key, the address and the */ +#define STRIP_ENCAP_SIZE(X) (32 + (X)*65L/64L) + +#define IS_RADIO_ADDRESS(p) ( \ + isdigit((p)[0]) && isdigit((p)[1]) && isdigit((p)[2]) && isdigit((p)[3]) && \ + (p)[4] == '-' && \ + isdigit((p)[5]) && isdigit((p)[6]) && isdigit((p)[7]) && isdigit((p)[8]) ) + +#define JIFFIE_TO_SEC(X) ((X) / HZ) + + +/************************************************************************/ +/* Utility routines */ typedef unsigned long InterruptStatus; @@ -144,62 +427,67 @@ restore_flags(x); } -/************************************************************************/ -/* Useful structures and definitions */ - -typedef struct { - __u8 c[32]; -} RadioName; - -typedef struct { - __u8 c[ 4]; -} MetricomKey; +static void DumpData(char *msg, struct strip *strip_info, __u8 *ptr, __u8 *end) +{ + static const int MAX_DumpData = 80; + __u8 pkt_text[MAX_DumpData], *p = pkt_text; -typedef union { - __u8 b[ 4]; - __u32 l; -} IPaddr; + *p++ = '\"'; -static const MetricomKey ProtocolKey = -{ + while (ptr= 32 && *ptr <= 126) + { + *p++ = *ptr; + } + else + { + sprintf(p, "\\%02X", *ptr); + p+= 3; + } + } + ptr++; } -}; -enum -{ - FALSE = 0, - TRUE = 1 -}; + if (ptr == end) + { + *p++ = '\"'; + } -#define LONG_TIME 0x7FFFFFFF + *p++ = 0; -typedef struct -{ - RadioName name; /* The address, with delimiters eg. *0000-1164* */ - MetricomKey key; /* Protocol type */ -} STRIP_Header; + printk(KERN_INFO "%s: %-13s%s\n", strip_info->dev.name, msg, pkt_text); +} -typedef struct +#if 0 +static void HexDump(char *msg, struct strip *strip_info, __u8 *start, __u8 *end) { - STRIP_Header h; - __u8 data[4]; /* Placeholder for payload (The IP packet) */ -} STRIP_Packet; + __u8 *ptr = start; + printk(KERN_INFO "%s: %s: %d bytes\n", strip_info->dev.name, msg, end-ptr); -/* - * STRIP_ENCAP_SIZE of an IP packet is the STRIP header at the front, - * byte-stuffing overhead of the payload, plus the CR at the end - */ - -#define STRIP_ENCAP_SIZE(X) (sizeof(STRIP_Header) + (X)*65L/64L + 2) - -/* - * Note: A Metricom packet looks like this: *
* - * eg. *0000-1164*SIP0 - */ + while (ptr < end) + { + long offset = ptr - start; + __u8 text[80], *p = text; + while (ptr < end && p < &text[16*3]) + { + *p++ = hextable[*ptr >> 4]; + *p++ = hextable[*ptr++ & 0xF]; + *p++ = ' '; + } + p[-1] = 0; + printk(KERN_INFO "%s: %4lX %s\n", strip_info->dev.name, offset, text); + } +} +#endif -static struct strip *struct_strip_list = NULL; /************************************************************************/ /* Byte stuffing/unstuffing routines */ @@ -212,14 +500,14 @@ * C0-FF Run of 1-64 zeroes (ASCII 0) */ -typedef enum +typedef enum { Stuff_Diff = 0x00, Stuff_DiffZero = 0x40, Stuff_Same = 0x80, Stuff_Zero = 0xC0, Stuff_NoCode = 0xFF, /* Special code, meaning no code selected */ - + Stuff_CodeMask = 0xC0, Stuff_CountMask = 0x3F, Stuff_MaxCount = 0x3F, @@ -244,431 +532,1156 @@ static __u8 *StuffData(__u8 *src, __u32 length, __u8 *dst, __u8 **code_ptr_ptr) { - __u8 *end = src + length; - __u8 *code_ptr = *code_ptr_ptr; - __u8 code = Stuff_NoCode, count = 0; - - if (!length) - return(dst); - - if (code_ptr) - { - /* - * Recover state from last call, if applicable - */ - code = (*code_ptr ^ Stuff_Magic) & Stuff_CodeMask; - count = (*code_ptr ^ Stuff_Magic) & Stuff_CountMask; - } + __u8 *end = src + length; + __u8 *code_ptr = *code_ptr_ptr; + __u8 code = Stuff_NoCode, count = 0; - while (src < end) - { - switch (code) - { - /* Stuff_NoCode: If no current code, select one */ - case Stuff_NoCode: - /* Record where we're going to put this code */ - code_ptr = dst++; - count = 0; /* Reset the count (zero means one instance) */ - /* Tentatively start a new block */ - if (*src == 0) - { - code = Stuff_Zero; - src++; - } - else - { - code = Stuff_Same; - *dst++ = *src++ ^ Stuff_Magic; - } - /* Note: We optimistically assume run of same -- */ - /* which will be fixed later in Stuff_Same */ - /* if it turns out not to be true. */ - break; - - /* Stuff_Zero: We already have at least one zero encoded */ - case Stuff_Zero: - /* If another zero, count it, else finish this code block */ - if (*src == 0) - { - count++; - src++; - } - else - { - StuffData_FinishBlock(Stuff_Zero + count); - } - break; - - /* Stuff_Same: We already have at least one byte encoded */ - case Stuff_Same: - /* If another one the same, count it */ - if ((*src ^ Stuff_Magic) == code_ptr[1]) - { - count++; - src++; - break; - } - /* else, this byte does not match this block. */ - /* If we already have two or more bytes encoded, */ - /* finish this code block */ - if (count) - { - StuffData_FinishBlock(Stuff_Same + count); - break; - } - /* else, we only have one so far, */ - /* so switch to Stuff_Diff code */ - code = Stuff_Diff; - /* and fall through to Stuff_Diff case below */ - /* Stuff_Diff: We have at least two *different* bytes encoded */ - case Stuff_Diff: - /* If this is a zero, must encode a Stuff_DiffZero, */ - /* and begin a new block */ - if (*src == 0) - { - StuffData_FinishBlock(Stuff_DiffZero + count); - } - /* else, if we have three in a row, it is worth starting */ - /* a Stuff_Same block */ - else if ((*src ^ Stuff_Magic)==dst[-1] && dst[-1]==dst[-2]) - { - /* Back off the last two characters we encoded */ - code += count-2; - /* Note: "Stuff_Diff + 0" is an illegal code */ - if (code == Stuff_Diff + 0) - { - code = Stuff_Same + 0; - } - StuffData_FinishBlock(code); - code_ptr = dst-2; - /* dst[-1] already holds the correct value */ - count = 2; /* 2 means three bytes encoded */ - code = Stuff_Same; - } - /* else, another different byte, so add it to the block */ - else - { - *dst++ = *src ^ Stuff_Magic; - count++; - } - src++; /* Consume the byte */ - break; - } - if (count == Stuff_MaxCount) - { - StuffData_FinishBlock(code + count); - } - } - if (code == Stuff_NoCode) - { - *code_ptr_ptr = NULL; - } - else - { - *code_ptr_ptr = code_ptr; - StuffData_FinishBlock(code + count); - } - return(dst); -} - -/* UnStuffData decodes the data at "src", up to (but not including) "end". -It writes the decoded data into the buffer pointed to by "dst", up to a -maximum of "dst_length", and returns the new value of "src" so that a -follow-on call can read more data, continuing from where the first left off. - -There are three types of results: -1. The source data runs out before extracting "dst_length" bytes: - UnStuffData returns NULL to indicate failure. -2. The source data produces exactly "dst_length" bytes: - UnStuffData returns new_src = end to indicate that all bytes were consumed. -3. "dst_length" bytes are extracted, with more remaining. - UnStuffData returns new_src < end to indicate that there are more bytes - to be read. - -Note: The decoding may be destructive, in that it may alter the source -data in the process of decoding it (this is necessary to allow a follow-on -call to resume correctly). */ + if (!length) + return(dst); + + if (code_ptr) + { + /* + * Recover state from last call, if applicable + */ + code = (*code_ptr ^ Stuff_Magic) & Stuff_CodeMask; + count = (*code_ptr ^ Stuff_Magic) & Stuff_CountMask; + } + + while (src < end) + { + switch (code) + { + /* Stuff_NoCode: If no current code, select one */ + case Stuff_NoCode: + /* Record where we're going to put this code */ + code_ptr = dst++; + count = 0; /* Reset the count (zero means one instance) */ + /* Tentatively start a new block */ + if (*src == 0) + { + code = Stuff_Zero; + src++; + } + else + { + code = Stuff_Same; + *dst++ = *src++ ^ Stuff_Magic; + } + /* Note: We optimistically assume run of same -- */ + /* which will be fixed later in Stuff_Same */ + /* if it turns out not to be true. */ + break; + + /* Stuff_Zero: We already have at least one zero encoded */ + case Stuff_Zero: + /* If another zero, count it, else finish this code block */ + if (*src == 0) + { + count++; + src++; + } + else + { + StuffData_FinishBlock(Stuff_Zero + count); + } + break; + + /* Stuff_Same: We already have at least one byte encoded */ + case Stuff_Same: + /* If another one the same, count it */ + if ((*src ^ Stuff_Magic) == code_ptr[1]) + { + count++; + src++; + break; + } + /* else, this byte does not match this block. */ + /* If we already have two or more bytes encoded, finish this code block */ + if (count) + { + StuffData_FinishBlock(Stuff_Same + count); + break; + } + /* else, we only have one so far, so switch to Stuff_Diff code */ + code = Stuff_Diff; + /* and fall through to Stuff_Diff case below */ + + /* Stuff_Diff: We have at least two *different* bytes encoded */ + case Stuff_Diff: + /* If this is a zero, must encode a Stuff_DiffZero, and begin a new block */ + if (*src == 0) + { + StuffData_FinishBlock(Stuff_DiffZero + count); + } + /* else, if we have three in a row, it is worth starting a Stuff_Same block */ + else if ((*src ^ Stuff_Magic)==dst[-1] && dst[-1]==dst[-2]) + { + /* Back off the last two characters we encoded */ + code += count-2; + /* Note: "Stuff_Diff + 0" is an illegal code */ + if (code == Stuff_Diff + 0) + { + code = Stuff_Same + 0; + } + StuffData_FinishBlock(code); + code_ptr = dst-2; + /* dst[-1] already holds the correct value */ + count = 2; /* 2 means three bytes encoded */ + code = Stuff_Same; + } + /* else, another different byte, so add it to the block */ + else + { + *dst++ = *src ^ Stuff_Magic; + count++; + } + src++; /* Consume the byte */ + break; + } + if (count == Stuff_MaxCount) + { + StuffData_FinishBlock(code + count); + } + } + if (code == Stuff_NoCode) + { + *code_ptr_ptr = NULL; + } + else + { + *code_ptr_ptr = code_ptr; + StuffData_FinishBlock(code + count); + } + return(dst); +} + +/* + * UnStuffData decodes the data at "src", up to (but not including) "end". + * It writes the decoded data into the buffer pointed to by "dst", up to a + * maximum of "dst_length", and returns the new value of "src" so that a + * follow-on call can read more data, continuing from where the first left off. + * + * There are three types of results: + * 1. The source data runs out before extracting "dst_length" bytes: + * UnStuffData returns NULL to indicate failure. + * 2. The source data produces exactly "dst_length" bytes: + * UnStuffData returns new_src = end to indicate that all bytes were consumed. + * 3. "dst_length" bytes are extracted, with more remaining. + * UnStuffData returns new_src < end to indicate that there are more bytes + * to be read. + * + * Note: The decoding may be destructive, in that it may alter the source + * data in the process of decoding it (this is necessary to allow a follow-on + * call to resume correctly). + */ static __u8 *UnStuffData(__u8 *src, __u8 *end, __u8 *dst, __u32 dst_length) { - __u8 *dst_end = dst + dst_length; - /* Sanity check */ - if (!src || !end || !dst || !dst_length) - return(NULL); - while (src < end && dst < dst_end) - { - int count = (*src ^ Stuff_Magic) & Stuff_CountMask; - switch ((*src ^ Stuff_Magic) & Stuff_CodeMask) - { - case Stuff_Diff: - if (src+1+count >= end) - return(NULL); - do - { - *dst++ = *++src ^ Stuff_Magic; - } - while(--count >= 0 && dst < dst_end); - if (count < 0) - src += 1; - else - { - if (count == 0) - *src = Stuff_Same ^ Stuff_Magic; - else - *src = (Stuff_Diff + count) ^ Stuff_Magic; - } - break; - case Stuff_DiffZero: - if (src+1+count >= end) - return(NULL); - do - { - *dst++ = *++src ^ Stuff_Magic; - } - while(--count >= 0 && dst < dst_end); - if (count < 0) - *src = Stuff_Zero ^ Stuff_Magic; - else - *src = (Stuff_DiffZero + count) ^ Stuff_Magic; - break; - case Stuff_Same: - if (src+1 >= end) - return(NULL); - do - { - *dst++ = src[1] ^ Stuff_Magic; - } - while(--count >= 0 && dst < dst_end); - if (count < 0) - src += 2; - else - *src = (Stuff_Same + count) ^ Stuff_Magic; - break; - case Stuff_Zero: - do - { - *dst++ = 0; - } - while(--count >= 0 && dst < dst_end); - if (count < 0) - src += 1; - else - *src = (Stuff_Zero + count) ^ Stuff_Magic; - break; - } - } - if (dst < dst_end) - return(NULL); - else - return(src); + __u8 *dst_end = dst + dst_length; + /* Sanity check */ + if (!src || !end || !dst || !dst_length) + return(NULL); + while (src < end && dst < dst_end) + { + int count = (*src ^ Stuff_Magic) & Stuff_CountMask; + switch ((*src ^ Stuff_Magic) & Stuff_CodeMask) + { + case Stuff_Diff: + if (src+1+count >= end) + return(NULL); + do + { + *dst++ = *++src ^ Stuff_Magic; + } + while(--count >= 0 && dst < dst_end); + if (count < 0) + src += 1; + else + { + if (count == 0) + *src = Stuff_Same ^ Stuff_Magic; + else + *src = (Stuff_Diff + count) ^ Stuff_Magic; + } + break; + case Stuff_DiffZero: + if (src+1+count >= end) + return(NULL); + do + { + *dst++ = *++src ^ Stuff_Magic; + } + while(--count >= 0 && dst < dst_end); + if (count < 0) + *src = Stuff_Zero ^ Stuff_Magic; + else + *src = (Stuff_DiffZero + count) ^ Stuff_Magic; + break; + case Stuff_Same: + if (src+1 >= end) + return(NULL); + do + { + *dst++ = src[1] ^ Stuff_Magic; + } + while(--count >= 0 && dst < dst_end); + if (count < 0) + src += 2; + else + *src = (Stuff_Same + count) ^ Stuff_Magic; + break; + case Stuff_Zero: + do + { + *dst++ = 0; + } + while(--count >= 0 && dst < dst_end); + if (count < 0) + src += 1; + else + *src = (Stuff_Zero + count) ^ Stuff_Magic; + break; + } + } + if (dst < dst_end) + return(NULL); + else + return(src); } + /************************************************************************/ /* General routines for STRIP */ -/* MTU has been changed by the IP layer. Unfortunately we are not told - * about this, but we spot it ourselves and fix things up. We could be in - * an upcall from the tty driver, or in an ip packet queue. +/* + * Convert a string to a Metricom Address. */ -static void strip_changedmtu(struct strip *strip_info) +static void string_to_radio_address(MetricomAddress *addr, __u8 *p) { - struct device *dev = &strip_info->dev; - unsigned char *tbuff, *rbuff, *sbuff, *otbuff, *orbuff, *osbuff; - int len; - InterruptStatus intstat; - - len = STRIP_ENCAP_SIZE(dev->mtu); - if (len < STRIP_ENCAP_SIZE(576)) - len = STRIP_ENCAP_SIZE(576); - - tbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC); - rbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC); - sbuff = (unsigned char *) kmalloc (len + 4, GFP_ATOMIC); - if (!tbuff || !rbuff || !sbuff) - { - printk("%s: unable to grow strip buffers, MTU change cancelled.\n", - strip_info->dev.name); - dev->mtu = strip_info->mtu; - if (tbuff) - kfree(tbuff); - if (rbuff) - kfree(rbuff); - if (sbuff) - kfree(sbuff); - return; - } - - intstat = DisableInterrupts(); - otbuff = strip_info->tx_buff; strip_info->tx_buff = tbuff; - orbuff = strip_info->rx_buff; strip_info->rx_buff = rbuff; - osbuff = strip_info->sx_buff; strip_info->sx_buff = sbuff; - if (strip_info->tx_left) - { - if (strip_info->tx_left <= len) - memcpy(strip_info->tx_buff, strip_info->tx_head, strip_info->tx_left); - else - { - strip_info->tx_left = 0; - strip_info->tx_dropped++; - } - } - strip_info->tx_head = strip_info->tx_buff; - - if (strip_info->sx_count) - { - if (strip_info->sx_count <= len) - memcpy(strip_info->sx_buff, osbuff, strip_info->sx_count); - else - { - strip_info->sx_count = 0; - strip_info->rx_over_errors++; - set_bit(STR_ERROR, &strip_info->flags); - } - } - - strip_info->mtu = STRIP_ENCAP_SIZE(dev->mtu); - strip_info->buffsize = len; - - RestoreInterrupts(intstat); - - if (otbuff != NULL) - kfree(otbuff); - if (orbuff != NULL) - kfree(orbuff); - if (osbuff != NULL) - kfree(osbuff); + addr->c[0] = 0; + addr->c[1] = 0; + addr->c[2] = READHEX(p[0]) << 4 | READHEX(p[1]); + addr->c[3] = READHEX(p[2]) << 4 | READHEX(p[3]); + addr->c[4] = READHEX(p[5]) << 4 | READHEX(p[6]); + addr->c[5] = READHEX(p[7]) << 4 | READHEX(p[8]); } -static void strip_unlock(struct strip *strip_info) +/* + * Convert a Metricom Address to a string. + */ + +static __u8 *radio_address_to_string(const MetricomAddress *addr, MetricomAddressString *p) { - strip_info->idle_timer.expires = jiffies + 2 * HZ; - add_timer(&strip_info->idle_timer); - if (!clear_bit(0, (void *)&strip_info->dev.tbusy)) - printk("%s: trying to unlock already unlocked device!\n", - strip_info->dev.name); + sprintf(p->c, "%02X%02X-%02X%02X", addr->c[2], addr->c[3], addr->c[4], addr->c[5]); + return(p->c); } -/************************************************************************/ -/* Sending routines */ +/* + * Note: Must make sure sx_size is big enough to receive a stuffed + * MAX_STRIP_MTU packet. Additionally, we also want to ensure that it's + * big enough to receive a large radio neighbour list (currently 4K). + */ -static void ResetRadio(struct strip *strip_info) -{ - static const char InitString[] = "ate0dt**starmode\r**"; - strip_info->watchdog_doprobe = jiffies + 10 * HZ; - strip_info->watchdog_doreset = jiffies + 1 * HZ; - strip_info->tty->driver.write(strip_info->tty, 0, - (char *)InitString, sizeof(InitString)-1); +static int allocate_buffers(struct strip *strip_info) +{ + struct device *dev = &strip_info->dev; + int stuffedlen = STRIP_ENCAP_SIZE(dev->mtu); + int sx_size = MAX(stuffedlen, 4096); + int tx_size = stuffedlen + sizeof(TickleString2); + __u8 *r = kmalloc(MAX_STRIP_MTU, GFP_ATOMIC); + __u8 *s = kmalloc(sx_size, GFP_ATOMIC); + __u8 *t = kmalloc(tx_size, GFP_ATOMIC); + if (r && s && t) + { + strip_info->rx_buff = r; + strip_info->sx_buff = s; + strip_info->tx_buff = t; + strip_info->sx_size = sx_size; + strip_info->tx_size = tx_size; + strip_info->mtu = dev->mtu; + return(1); + } + if (r) kfree(r); + if (s) kfree(s); + if (t) kfree(t); + return(0); } /* - * Called by the driver when there's room for more data. If we have - * more packets to send, we send them here. + * MTU has been changed by the IP layer. Unfortunately we are not told + * about this, but we spot it ourselves and fix things up. We could be in + * an upcall from the tty driver, or in an ip packet queue. */ -static void strip_write_some_more(struct tty_struct *tty) +static void strip_changedmtu(struct strip *strip_info) { - InterruptStatus intstat; - int num_written; - struct strip *strip_info = (struct strip *) tty->disc_data; - - /* First make sure we're connected. */ - if (!strip_info || strip_info->magic != STRIP_MAGIC || !strip_info->dev.start) - return; - - if (strip_info->tx_left > 0) - { /* If some data left, send it */ - /* Must disable interrupts because otherwise the write_wakeup might - * happen before we've had a chance to update the tx_left and - * tx_head fields - */ - intstat = DisableInterrupts(); - num_written = tty->driver.write(tty, 0, strip_info->tx_head, strip_info->tx_left); - strip_info->tx_left -= num_written; - strip_info->tx_head += num_written; - RestoreInterrupts(intstat); - } - else /* Else start transmission of another packet */ - { - tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); - strip_unlock(strip_info); - mark_bh(NET_BH); - } -} + int old_mtu = strip_info->mtu; + struct device *dev = &strip_info->dev; + unsigned char *orbuff = strip_info->rx_buff; + unsigned char *osbuff = strip_info->sx_buff; + unsigned char *otbuff = strip_info->tx_buff; + InterruptStatus intstat; + if (dev->mtu > MAX_STRIP_MTU) + { + printk(KERN_ERR "%s: MTU exceeds maximum allowable (%d), MTU change cancelled.\n", + strip_info->dev.name, MAX_STRIP_MTU); + dev->mtu = old_mtu; + return; + } -/* Encapsulate one IP datagram. */ + /* + * Have to disable interrupts here because we're reallocating and resizing + * the serial buffers, and we can't have data arriving in them while we're + * moving them around in memory. This may cause data to be lost on the serial + * port, but hopefully people won't change MTU that often. + * Also note, this may not work on a symmetric multi-processor system. + */ + intstat = DisableInterrupts(); -static unsigned char *strip_stuff(unsigned char *ptr, struct strip *strip_info, struct sk_buff *skb) -{ - __u8 *start; - __u8 *stuffstate = NULL; - unsigned char *icp = skb->data; - int len = skb->len; - MetricomAddress haddr; + if (!allocate_buffers(strip_info)) + { + RestoreInterrupts(intstat); + printk(KERN_ERR "%s: unable to grow strip buffers, MTU change cancelled.\n", + strip_info->dev.name); + dev->mtu = old_mtu; + return; + } - if (len > strip_info->mtu) { /* Sigh, shouldn't occur BUT ... */ - printk("%s: Dropping oversized transmit packet!\n", strip_info->dev.name); - strip_info->tx_dropped++; - return(NULL); + if (strip_info->sx_count) + { + if (strip_info->sx_count <= strip_info->sx_size) + memcpy(strip_info->sx_buff, osbuff, strip_info->sx_count); + else + { + strip_info->sx_count = 0; + strip_info->rx_over_errors++; + strip_info->discard = 1; + } } - if (!arp_query(haddr.c, skb->raddr, &strip_info->dev)) { - IPaddr a,b,c; - a.l = skb->raddr; - b.l = skb->saddr; - c.l = skb->daddr; - printk("%s: Unknown dest %d.%d.%d.%d s=%d.%d.%d.%d d=%d.%d.%d.%d\n", - strip_info->dev.name, - a.b[0], a.b[1], a.b[2], a.b[3], - b.b[0], b.b[1], b.b[2], b.b[3], - c.b[0], c.b[1], c.b[2], c.b[3]); - strip_info->tx_dropped++; - return(NULL); + if (strip_info->tx_left) + { + if (strip_info->tx_left <= strip_info->tx_size) + memcpy(strip_info->tx_buff, strip_info->tx_head, strip_info->tx_left); + else + { + strip_info->tx_left = 0; + strip_info->tx_dropped++; + } } + strip_info->tx_head = strip_info->tx_buff; - *ptr++ = '*'; - ptr[3] = '0' + haddr.s[0] % 10; haddr.s[0] /= 10; - ptr[2] = '0' + haddr.s[0] % 10; haddr.s[0] /= 10; - ptr[1] = '0' + haddr.s[0] % 10; haddr.s[0] /= 10; - ptr[0] = '0' + haddr.s[0] % 10; - ptr+=4; - *ptr++ = '-'; - ptr[3] = '0' + haddr.s[1] % 10; haddr.s[1] /= 10; - ptr[2] = '0' + haddr.s[1] % 10; haddr.s[1] /= 10; - ptr[1] = '0' + haddr.s[1] % 10; haddr.s[1] /= 10; - ptr[0] = '0' + haddr.s[1] % 10; - ptr+=4; - *ptr++ = '*'; - *ptr++ = ProtocolKey.c[0]; /* Protocol key */ - *ptr++ = ProtocolKey.c[1]; - *ptr++ = ProtocolKey.c[2]; - *ptr++ = ProtocolKey.c[3]; + RestoreInterrupts(intstat); - start = ptr; - ptr = StuffData(icp, len, ptr, &stuffstate); /* Make payload */ + printk(KERN_NOTICE "%s: strip MTU changed fom %d to %d.\n", + strip_info->dev.name, old_mtu, strip_info->mtu); - *ptr++ = 0x0D; /* Put on final delimiter */ - return(ptr); + if (orbuff) kfree(orbuff); + if (osbuff) kfree(osbuff); + if (otbuff) kfree(otbuff); } -/* Encapsulate one IP datagram and stuff into a TTY queue. */ -static void strip_send(struct strip *strip_info, struct sk_buff *skb) +static void strip_unlock(struct strip *strip_info) { - unsigned char *ptr; - - /* See if someone has been ifconfigging */ - if (strip_info->mtu != STRIP_ENCAP_SIZE(strip_info->dev.mtu)) - strip_changedmtu(strip_info); + /* + * Set the time to go off in one second. + */ + strip_info->idle_timer.expires = jiffies + HZ; + add_timer(&strip_info->idle_timer); + if (!clear_bit(0, (void *)&strip_info->dev.tbusy)) + printk(KERN_ERR "%s: trying to unlock already unlocked device!\n", + strip_info->dev.name); +} + + +/************************************************************************/ +/* Callback routines for exporting information through /proc */ + +#if DO_PROC_NET_STRIP_STATUS | DO_PROC_NET_STRIP_TRACE + +/* + * This function updates the total amount of data printed so far. It then + * determines if the amount of data printed into a buffer has reached the + * offset requested. If it hasn't, then the buffer is shifted over so that + * the next bit of data can be printed over the old bit. If the total + * amount printed so far exceeds the total amount requested, then this + * function returns 1, otherwise 0. + */ +static int +shift_buffer(char *buffer, int requested_offset, int requested_len, + int *total, int *slop, char **buf) +{ + int printed; + + /* printk(KERN_DEBUG "shift: buffer: %d o: %d l: %d t: %d buf: %d\n", + (int) buffer, requested_offset, requested_len, *total, + (int) *buf); */ + printed = *buf - buffer; + if (*total + printed <= requested_offset) { + *total += printed; + *buf = buffer; + } + else { + if (*total < requested_offset) { + *slop = requested_offset - *total; + } + *total = requested_offset + printed - *slop; + } + if (*total > requested_offset + requested_len) { + return 1; + } + else { + return 0; + } +} + +/* + * This function calculates the actual start of the requested data + * in the buffer. It also calculates actual length of data returned, + * which could be less that the amount of data requested. + */ +static int +calc_start_len(char *buffer, char **start, int requested_offset, + int requested_len, int total, char *buf) +{ + int return_len, buffer_len; + + buffer_len = buf - buffer; + if (buffer_len >= STRIP_PROC_BUFFER_SIZE - 1) { + printk(KERN_ERR "STRIP: exceeded /proc buffer size\n"); + } + + /* + * There may be bytes before and after the + * chunk that was actually requested. + */ + return_len = total - requested_offset; + if (return_len < 0) { + return_len = 0; + } + *start = buf - return_len; + if (return_len > requested_len) { + return_len = requested_len; + } + /* printk(KERN_DEBUG "return_len: %d\n", return_len); */ + return return_len; +} + +#endif DO_PROC_NET_STRIP_STATUS | DO_PROC_NET_STRIP_TRACE + +#if DO_PROC_NET_STRIP_STATUS + +/* + * If the time is in the near future, time_delta prints the number of + * seconds to go into the buffer and returns the address of the buffer. + * If the time is not in the near future, it returns the address of the + * string "Not scheduled" The buffer must be long enough to contain the + * ascii representation of the number plus 9 charactes for the " seconds" + * and the null character. + */ +static char *time_delta(char buffer[], long time) +{ + time -= jiffies; + if (time > LongTime / 2) return("Not scheduled"); + if(time < 0) time = 0; /* Don't print negative times */ + sprintf(buffer, "%ld seconds", time / HZ); + return(buffer); +} + +/* + * This function prints radio status information into the specified + * buffer. + */ +static int +sprintf_status_info(char *buffer, struct strip *strip_info) +{ + char temp_buffer[32]; + MetricomAddressString addr_string; + char *buf; + + buf = buffer; + buf += sprintf(buf, "Interface name\t\t%s\n", strip_info->if_name); + buf += sprintf(buf, " Radio working:\t\t%s\n", + strip_info->working && + (long)jiffies - strip_info->watchdog_doreset < 0 ? "Yes" : "No"); + (void) radio_address_to_string((MetricomAddress *) + &strip_info->dev.dev_addr, + &addr_string); + buf += sprintf(buf, " Device address:\t%s\n", addr_string.c); + buf += sprintf(buf, " Firmware version:\t%s\n", + !strip_info->working ? "Unknown" : + !strip_info->structured_messages ? "Should be upgraded" : + strip_info->firmware_version.c); + buf += sprintf(buf, " Serial number:\t\t%s\n", strip_info->serial_number.c); + buf += sprintf(buf, " Battery voltage:\t%s\n", strip_info->battery_voltage.c); + buf += sprintf(buf, " Transmit queue (bytes):%d\n", strip_info->tx_left); + buf += sprintf(buf, " Next watchdog probe:\t%s\n", + time_delta(temp_buffer, strip_info->watchdog_doprobe)); + buf += sprintf(buf, " Next watchdog reset:\t%s\n", + time_delta(temp_buffer, strip_info->watchdog_doreset)); + buf += sprintf(buf, " Next gratuitous ARP:\t%s\n", + time_delta(temp_buffer, strip_info->gratuitous_arp)); + buf += sprintf(buf, " Next ARP interval:\t%ld seconds\n", + JIFFIE_TO_SEC(strip_info->arp_interval)); + return buf - buffer; +} + +static int +sprintf_portables(char *buffer, struct strip *strip_info) +{ + + MetricomAddressString addr_string; + MetricomNode *node; + char *buf; + + buf = buffer; + buf += sprintf(buf, " portables: name\t\tpoll_latency\tsignal strength\n"); + for (node = strip_info->neighbor_list; node != NULL; + node = node->next) { + if (!(node->type & NodeValid)) { + break; + } + if (node->type & NodeHasWAN) { + continue; + } + (void) radio_address_to_string(&node->addr, &addr_string); + buf += sprintf(buf, " %s\t\t\t\t%d\t\t%d\n", + addr_string.c, node->poll_latency, node->rssi); + } + return buf - buffer; +} + +static int +sprintf_poletops(char *buffer, struct strip *strip_info) +{ + MetricomNode *node; + char *buf; + + buf = buffer; + buf += sprintf(buf, " poletops: GPS\t\t\tpoll_latency\tsignal strength\n"); + for (node = strip_info->neighbor_list; + node != NULL; node = node->next) { + if (!(node->type & NodeValid)) { + break; + } + if (!(node->type & NodeHasWAN)) { + continue; + } + buf += sprintf(buf, " %s\t\t\t%d\t\t%d\n", + node->gl.s, node->poll_latency, node->rssi); + } + return buf - buffer; +} + +/* + * This function is exports status information from the STRIP driver through + * the /proc file system. /proc filesystem should be fixed: + * 1) slow (sprintfs here, a memory copy in the proc that calls this one) + * 2) length of buffer not passed + * 3) dummy isn't client data set when the callback was registered + * 4) poorly documented (this function is called until the requested amount + * of data is returned, buffer is only 4K long, dummy is the permissions + * of the file (?), the proc_dir_entry passed to proc_net_register must + * be kmalloc-ed) + */ - ptr = strip_info->tx_buff; +static int +strip_get_status_info(char *buffer, char **start, off_t requested_offset, + int requested_len, int dummy) +{ + char *buf; + int total = 0, slop = 0, len_exceeded; + InterruptStatus i_status; + struct strip *strip_info; + + buf = buffer; + buf += sprintf(buf, "strip_version: %s\n", StripVersion); + + i_status = DisableInterrupts(); + strip_info = struct_strip_list; + RestoreInterrupts(i_status); + + while (strip_info != NULL) { + i_status = DisableInterrupts(); + buf += sprintf_status_info(buf, strip_info); + RestoreInterrupts(i_status); + len_exceeded = shift_buffer(buffer, requested_offset, requested_len, + &total, &slop, &buf); + if (len_exceeded) { + goto done; + } + strip_info->neighbor_list_locked = TRUE; + buf += sprintf_portables(buf, strip_info); + strip_info->neighbor_list_locked = FALSE; + len_exceeded = shift_buffer(buffer, requested_offset, requested_len, + &total, &slop, &buf); + if (len_exceeded) { + goto done; + } + strip_info->neighbor_list_locked = TRUE; + buf += sprintf_poletops(buf, strip_info); + strip_info->neighbor_list_locked = FALSE; + len_exceeded = shift_buffer(buffer, requested_offset, requested_len, + &total, &slop, &buf); + if (len_exceeded) { + goto done; + } + strip_info = strip_info->next; + } +done: + return calc_start_len(buffer, start, requested_offset, requested_len, + total, buf); +} + +#endif DO_PROC_NET_STRIP_STATUS + +#if DO_PROC_NET_STRIP_TRACE + +/* + * Convert an Ethernet protocol to a string + * Returns the number of characters printed. + */ + +static int protocol_to_string(int protocol, __u8 *p) +{ + int printed; + + switch (protocol) { + case ETH_P_IP: + printed = sprintf(p, "IP"); + break; + case ETH_P_ARP: + printed = sprintf(p, "ARP"); + break; + default: + printed = sprintf(p, "%d", protocol); + } + return printed; +} + +static int +sprintf_log_entry(char *buffer, struct strip *strip_info, int packet_index) +{ + StripLog *entry; + MetricomAddressString addr_string; + __u8 sig_buf[24], *s; + char *buf, proto_buf[10]; + + entry = &strip_info->packetLog[packet_index]; + if (!entry->valid) { + return 0; + } + buf = buffer; + buf += sprintf(buf, "%-4s %s %7lu ", strip_info->if_name, + ENTRY_TYPE_TO_STRING(entry->entry_type), entry->seqNum); + (void) protocol_to_string(entry->packet_type, proto_buf); + buf += sprintf(buf, "%-4s", proto_buf); + s = entry->sig.print_sig; + sprintf(sig_buf, "%d.%d.%d.%d.%d.%d", s[0], s[1], s[2], s[3], s[4], s[5]); + buf += sprintf(buf, "%-24s", sig_buf); + (void) radio_address_to_string((MetricomAddress *) &entry->src, + &addr_string); + buf += sprintf(buf, "%-10s", addr_string.c); + (void) radio_address_to_string((MetricomAddress *) &entry->dest, + &addr_string); + buf += sprintf(buf, "%-10s", addr_string.c); + buf += sprintf(buf, "%8d %6d %5lu %6lu %5lu\n", entry->timeStamp.tv_sec, + entry->timeStamp.tv_usec, entry->rawSize, + entry->stripSize, entry->slipSize); + return buf - buffer; +} + +/* + * This function exports trace information from the STRIP driver through the + * /proc file system. + */ + +static int +strip_get_trace_info(char *buffer, char **start, off_t requested_offset, + int requested_len, int dummy) +{ + char *buf; + int len_exceeded, total = 0, slop = 0, packet_index, oldest; + InterruptStatus i_status; + struct strip *strip_info; + + buf = buffer; + buf += sprintf(buf, "if s/r seqnum t signature "); + buf += sprintf(buf, + "src dest sec usec raw strip slip\n"); + + i_status = DisableInterrupts(); + strip_info = struct_strip_list; + oldest = strip_info->next_entry; + RestoreInterrupts(i_status); + + /* + * If we disable interrupts for this entire loop, + * characters from the serial port could be lost, + * so we only disable interrupts when accessing + * a log entry. If more than STRIP_LOG_INT_SIZE + * packets are logged before the first entry is + * printed, then some of the entries could be + * printed out of order. + */ + while (strip_info != NULL) { + for (packet_index = oldest + STRIP_LOG_INT_SIZE; + packet_index != oldest; + packet_index = (packet_index + 1) % + ELEMENTS_OF(strip_info->packetLog)) { + i_status = DisableInterrupts(); + buf += sprintf_log_entry(buf, strip_info, packet_index); + RestoreInterrupts(i_status); + len_exceeded = shift_buffer(buffer, requested_offset, + requested_len, &total, &slop, &buf); + if (len_exceeded) { + goto done; + } + } + strip_info = strip_info->next; + } +done: + return calc_start_len(buffer, start, requested_offset, requested_len, + total, buf); +} + +static int slip_len(unsigned char *data, int len) +{ + static const unsigned char SLIP_END=0300; /* indicates end of SLIP frame */ + static const unsigned char SLIP_ESC=0333; /* indicates SLIP byte stuffing */ + int count = len; + while (--len >= 0) + { + if (*data == SLIP_END || *data == SLIP_ESC) count++; + data++; + } + return(count); +} + +/* Copied from kernel/sched.c */ +static void jiffiestotimeval(unsigned long jiffies, struct timeval *value) +{ + value->tv_usec = (jiffies % HZ) * (1000000.0 / HZ); + value->tv_sec = jiffies / HZ; + return; +} + +/* + * This function logs a packet. + * A pointer to the packet itself is passed so that some of the data can be + * used to compute a signature. The pointer should point the the + * part of the packet following the STRIP_header. + */ + +static void packet_log(struct strip *strip_info, __u8 *packet, + LogEntry entry_type, STRIP_Header *hdr, + int raw_size, int strip_size, int slip_size) +{ + StripLog *entry; + struct iphdr *iphdr; + struct arphdr *arphdr; + + entry = &strip_info->packetLog[strip_info->next_entry]; + if (entry_type == EntrySend) { + entry->seqNum = strip_info->num_sent++; + } + else { + entry->seqNum = strip_info->num_received++; + } + entry->entry_type = entry_type; + entry->packet_type = ntohs(hdr->protocol); + switch (entry->packet_type) { + case ETH_P_IP: + /* + * The signature for IP is the sender's ip address and + * the identification field. + */ + iphdr = (struct iphdr *) packet; + entry->sig.ip_sig.id = iphdr->id; + entry->sig.ip_sig.src.l = iphdr->saddr; + break; + case ETH_P_ARP: + /* + * The signature for ARP is the sender's ip address and + * the operation. + */ + arphdr = (struct arphdr *) packet; + entry->sig.arp_sig.op = arphdr->ar_op; + memcpy(&entry->sig.arp_sig.src.l, packet + 8 + arphdr->ar_hln, + sizeof(entry->sig.arp_sig.src.l)); + entry->sig.arp_sig.src.l = entry->sig.arp_sig.src.l; + break; + default: + printk(KERN_DEBUG "STRIP: packet_log: unknown packet type: %d\n", + entry->packet_type); + break; + } + memcpy(&entry->src, &hdr->src_addr, sizeof(MetricomAddress)); + memcpy(&entry->dest, &hdr->dst_addr, sizeof(MetricomAddress)); + + jiffiestotimeval(jiffies, &(entry->timeStamp)); + entry->rawSize = raw_size; + entry->stripSize = strip_size; + entry->slipSize = slip_size; + entry->valid = 1; + + strip_info->next_entry = (strip_info->next_entry + 1) % + ELEMENTS_OF(strip_info->packetLog); +} + +#endif DO_PROC_NET_STRIP_TRACE + +/* + * This function parses the response to the ATS300? command, + * extracting the radio version and serial number. + */ +static void get_radio_version(struct strip *strip_info, __u8 *ptr, __u8 *end) +{ + __u8 *p, *value_begin, *value_end; + int len; + + /* Determine the beginning of the second line of the payload */ + p = ptr; + while (p < end && *p != 10) p++; + if (p >= end) return; + p++; + value_begin = p; + + /* Determine the end of line */ + while (p < end && *p != 10) p++; + if (p >= end) return; + value_end = p; + p++; + + len = value_end - value_begin; + len = MIN(len, sizeof(MetricomFirmwareVersion) - 1); + sprintf(strip_info->firmware_version.c, "%.*s", len, value_begin); + + /* Look for the first colon */ + while (p < end && *p != ':') p++; + if (p >= end) return; + /* Skip over the space */ + p += 2; + len = sizeof(MetricomSerialNumber) - 1; + if (p + len <= end) { + sprintf(strip_info->serial_number.c, "%.*s", len, p); + } + else { + printk(KERN_ERR "STRIP: radio serial number shorter (%d) than expected (%d)\n", + end - p, len); + } +} + +/* + * This function parses the response to the ATS325? command, + * extracting the radio battery voltage. + */ +static void get_radio_voltage(struct strip *strip_info, __u8 *ptr, __u8 *end) +{ + int len; + + len = sizeof(MetricomBatteryVoltage) - 1; + if (ptr + len <= end) { + sprintf(strip_info->battery_voltage.c, "%.*s", len, ptr); + } + else { + printk(KERN_ERR "STRIP: radio voltage string shorter (%d) than expected (%d)\n", + end - ptr, len); + } +} + +/* + * This function parses the response to the AT~I2 command, + * which gives the names of the radio's nearest neighbors. + * It relies on the format of the response. + */ +static void get_radio_neighbors(struct strip *strip_info, __u8 *ptr, __u8 *end) +{ + __u8 *p, *line_begin; + int num_nodes_reported, num_nodes_counted; + MetricomNode *node, *last; + + /* Check if someone is reading the list */ + if (strip_info->neighbor_list_locked) { + return; + } + + /* Determine the number of Nodes */ + p = ptr; + num_nodes_reported = simple_strtoul(p, NULL, 10); + /* printk(KERN_DEBUG "num_nodes: %d\n", num_nodes_reported); */ + + /* Determine the beginning of the next line */ + while (p < end && *p != 10) p++; + if (p >= end) return; + p++; + + /* + * The node list should never be empty because we allocate one empty + * node when the strip_info is allocated. The nodes which were allocated + * when the number of neighbors was high but are no longer needed because + * there aren't as many neighbors any more are marked invalid. Invalid nodes + * are kept at the end of the list. + */ + node = strip_info->neighbor_list; + last = node; + if (node == NULL) { + DumpData("Neighbor list is NULL:", strip_info, p, end); + return; + } + line_begin = p; + num_nodes_counted = 0; + while (line_begin < end) { + /* Check to see if the format is what we expect. */ + if ((line_begin + STRIP_NODE_LEN) > end) { + printk(KERN_ERR "STRIP: radio neighbor node string shorter (%d) than expected (%d)\n", + end - line_begin, STRIP_NODE_LEN); + break; + } + + /* Get a node */ + if (node == NULL) { + node = kmalloc(sizeof(MetricomNode), GFP_ATOMIC); + node->next = NULL; + } + node->type = NodeValid; + + /* Fill the node in */ + + /* Determine if it has a GPS location and fill it in if it does. */ + p = line_begin; + /* printk(KERN_DEBUG "node: %64s\n", p); */ + if (p[0] != STRIP_PORTABLE_CHAR) { + node->type |= NodeHasWAN; + sprintf(node->gl.s, "%.*s", (int) sizeof(GeographicLocation) - 1, p); + } + + /* Determine if it is a router */ + p = line_begin + 18; + if (p[0] == STRIP_ROUTER_CHAR) { + node->type |= NodeIsRouter; + } + + /* Could be a radio address or some weird poletop address. */ + p = line_begin + 20; + /* printk(KERN_DEBUG "before addr: %6s\n", p); */ + string_to_radio_address(&node->addr, p); + /* radio_address_to_string(&node->addr, addr_string); + printk(KERN_DEBUG "after addr: %s\n", addr_string); */ + + if (IS_RADIO_ADDRESS(p)) { + string_to_radio_address(&node->addr, p); + } + else { + memset(&node->addr, 0, sizeof(MetricomAddress)); + } + + /* Get the poll latency. %$#!@ simple_strtoul can't skip white space */ + p = line_begin + 41; + while (isspace(*p) && (p < end)) { + p++; + } + node->poll_latency = simple_strtoul(p, NULL, 10); + + /* Get the signal strength. simple_strtoul doesn't do minus signs */ + p = line_begin + 60; + node->rssi = -simple_strtoul(p, NULL, 10); + + if (last != node) { + last->next = node; + last = node; + } + node = node->next; + line_begin += STRIP_NODE_LEN; + num_nodes_counted++; + } + + /* invalidate all remaining nodes */ + for (;node != NULL; node = node->next) { + node->type &= ~NodeValid; + } + + /* + * If the number of nodes reported is different + * from the number counted, might need to up the number + * requested. + */ + if (num_nodes_reported != num_nodes_counted) { + printk(KERN_DEBUG "nodes reported: %d \tnodes counted: %d\n", + num_nodes_reported, num_nodes_counted); + } +} + + +/************************************************************************/ +/* Sending routines */ + +static void ResetRadio(struct strip *strip_info) +{ + static const char InitString[] = "\rat\r\rate0q1dt**starmode\r\r**"; + + /* If the radio isn't working anymore, we should clear the old status information. */ + if (strip_info->working) + { + printk(KERN_INFO "%s: No response: Resetting radio.\n", strip_info->dev.name); + strip_info->firmware_version.c[0] = '\0'; + strip_info->serial_number.c[0] = '\0'; + strip_info->battery_voltage.c[0] = '\0'; + } + /* Mark radio address as unknown */ + *(MetricomAddress*)&strip_info->dev.dev_addr = zero_address; + strip_info->working = FALSE; + strip_info->structured_messages = FALSE; + strip_info->watchdog_doprobe = jiffies + 10 * HZ; + strip_info->watchdog_doreset = jiffies + 1 * HZ; + strip_info->tty->driver.write(strip_info->tty, 0, (char *)InitString, sizeof(InitString)-1); +} + +/* + * Called by the driver when there's room for more data. If we have + * more packets to send, we send them here. + */ + +static void strip_write_some_more(struct tty_struct *tty) +{ + struct strip *strip_info = (struct strip *) tty->disc_data; + + /* First make sure we're connected. */ + if (!strip_info || strip_info->magic != STRIP_MAGIC || !strip_info->dev.start) + return; + + if (strip_info->tx_left > 0) + { + /* + * If some data left, send it + * Note: There's a kernel design bug here. The write_wakeup routine has to + * know how many bytes were written in the previous call, but the number of + * bytes written is returned as the result of the tty->driver.write call, + * and there's no guarantee that the tty->driver.write routine will have + * returned before the write_wakeup routine is invoked. If the PC has fast + * Serial DMA hardware, then it's quite possible that the write could complete + * almost instantaneously, meaning that my write_wakeup routine could be + * called immediately, before tty->driver.write has had a chance to return + * the number of bytes that it wrote. In an attempt to guard against this, + * I disable interrupts around the call to tty->driver.write, although even + * this might not work on a symmetric multi-processor system. + */ + InterruptStatus intstat = DisableInterrupts(); + int num_written = tty->driver.write(tty, 0, strip_info->tx_head, strip_info->tx_left); + strip_info->tx_left -= num_written; + strip_info->tx_head += num_written; + RestoreInterrupts(intstat); + } + else /* Else start transmission of another packet */ + { + tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + strip_unlock(strip_info); + mark_bh(NET_BH); + } +} + +static unsigned char *strip_make_packet(unsigned char *ptr, struct strip *strip_info, struct sk_buff *skb) +{ +#if DO_PROC_NET_STRIP_TRACE + unsigned char *start_ptr; +#endif DO_PROC_NET_STRIP_TRACE + + __u8 *stuffstate = NULL; + STRIP_Header *header = (STRIP_Header *)skb->data; + MetricomAddress haddr = header->dst_addr; + int len = skb->len - sizeof(STRIP_Header); + MetricomKey key; + + /*HexDump("strip_make_packet", strip_info, skb->data, skb->data + skb->len);*/ + + if (header->protocol == htons(ETH_P_IP)) key = SIP0Key; + else if (header->protocol == htons(ETH_P_ARP)) key = ARP0Key; + else + { + printk(KERN_ERR "%s: strip_make_packet: Unknown packet type 0x%04X\n", + strip_info->dev.name, ntohs(header->protocol)); + strip_info->tx_dropped++; + return(NULL); + } + + if (len > strip_info->mtu) + { + printk(KERN_ERR "%s: Dropping oversized transmit packet: %d bytes\n", + strip_info->dev.name, len); + strip_info->tx_dropped++; + return(NULL); + } + + /* + * If this is a broadcast packet, send it to our designated Metricom + * 'broadcast hub' radio (First byte of address being 0xFF means broadcast) + */ + if (haddr.c[0] == 0xFF) + { + /*IPaddr a; + a.l = strip_info->dev.pa_brdaddr; + printk(KERN_INFO "%s: Broadcast packet! Sending to %d.%d.%d.%d\n", + strip_info->dev.name, a.b[0], a.b[1], a.b[2], a.b[3]);*/ + + if (!arp_query(haddr.c, strip_info->dev.pa_brdaddr, &strip_info->dev)) + { + /*IPaddr a; + a.l = strip_info->dev.pa_brdaddr; + printk(KERN_INFO "%s: No ARP cache entry for %d.%d.%d.%d\n", + strip_info->dev.name, a.b[0], a.b[1], a.b[2], a.b[3]); + strip_info->tx_dropped++;*/ + return(NULL); + } + } + + *ptr++ = '*'; + *ptr++ = hextable[haddr.c[2] >> 4]; + *ptr++ = hextable[haddr.c[2] & 0xF]; + *ptr++ = hextable[haddr.c[3] >> 4]; + *ptr++ = hextable[haddr.c[3] & 0xF]; + *ptr++ = '-'; + *ptr++ = hextable[haddr.c[4] >> 4]; + *ptr++ = hextable[haddr.c[4] & 0xF]; + *ptr++ = hextable[haddr.c[5] >> 4]; + *ptr++ = hextable[haddr.c[5] & 0xF]; + *ptr++ = '*'; + *ptr++ = key.c[0]; + *ptr++ = key.c[1]; + *ptr++ = key.c[2]; + *ptr++ = key.c[3]; + +#if DO_PROC_NET_STRIP_TRACE + start_ptr = ptr; +#endif DO_PROC_NET_STRIP_TRACE + + ptr = StuffData(skb->data + sizeof(STRIP_Header), len, ptr, &stuffstate); + +#if DO_PROC_NET_STRIP_TRACE + packet_log(strip_info, skb->data + sizeof(STRIP_Header), EntrySend, + header, len, ptr-start_ptr, + slip_len(skb->data + sizeof(STRIP_Header), len)); +#endif DO_PROC_NET_STRIP_TRACE + + *ptr++ = 0x0D; + return(ptr); +} + +static void strip_send(struct strip *strip_info, struct sk_buff *skb) +{ + unsigned char *ptr = strip_info->tx_buff; /* If we have a packet, encapsulate it and put it in the buffer */ - if (skb) { - ptr = strip_stuff(ptr, strip_info, skb); + if (skb) + { + ptr = strip_make_packet(ptr, strip_info, skb); /* If error, unlock and return */ if (!ptr) { strip_unlock(strip_info); return; } - strip_info->tx_packets++; /* Count another successful packet */ + strip_info->tx_packets++; /* Count another successful packet */ + /*DumpData("Sending:", strip_info, strip_info->tx_buff, ptr);*/ + /*HexDump("Sending", strip_info, strip_info->tx_buff, ptr);*/ } /* Set up the strip_info ready to send the data */ @@ -677,238 +1690,528 @@ strip_info->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); /* If watchdog has expired, reset the radio */ - if ((long)jiffies - strip_info->watchdog_doreset >= 0) { - printk("%s: No response: Resetting radio.\n", strip_info->dev.name); + if ((long)jiffies - strip_info->watchdog_doreset >= 0) + { ResetRadio(strip_info); + return; /* Note: if there's a packet to send, strip_write_some_more will do it after the reset has finished */ + } + + /* No reset. + * If it is time for another tickle, tack it on the end of the packet + */ + if ((long)jiffies - strip_info->watchdog_doprobe >= 0) + { + /* Send tickle to make radio protest */ + /*printk(KERN_INFO "%s: Routine radio test.\n", strip_info->dev.name);*/ + const char *TickleString = TickleString1; + int length = sizeof(TickleString1)-1; + if (strip_info->structured_messages) + { + TickleString = TickleString2; + length = sizeof(TickleString2)-1; + } + memcpy(ptr, TickleString, length); + strip_info->tx_left += length; + strip_info->watchdog_doprobe = jiffies + 10 * HZ; + strip_info->watchdog_doreset = jiffies + 1 * HZ; + } + + /* + * If it is time for a periodic ARP, queue one up to be sent + */ + if (strip_info->working && (long)jiffies - strip_info->gratuitous_arp >= 0 && + memcmp(strip_info->dev.dev_addr, zero_address.c, sizeof(zero_address))) + { + /*printk(KERN_INFO "%s: Sending gratuitous ARP with interval %ld\n", + strip_info->dev.name, strip_info->arp_interval / HZ);*/ + strip_info->gratuitous_arp = jiffies + strip_info->arp_interval; + strip_info->arp_interval *= 2; + if (strip_info->arp_interval > MaxARPInterval) + strip_info->arp_interval = MaxARPInterval; + arp_send(ARPOP_REPLY, ETH_P_ARP, strip_info->dev.pa_addr, + &strip_info->dev, strip_info->dev.pa_addr, + NULL, strip_info->dev.dev_addr, NULL); + } + + if (strip_info->tx_size - strip_info->tx_left < 20) + printk(KERN_ERR "%s: Sending%5d bytes;%5d bytes free.\n", strip_info->dev.name, + strip_info->tx_left, strip_info->tx_size - strip_info->tx_left); + + /* All ready. Start the transmission */ + strip_write_some_more(strip_info->tty); +} + +/* Encapsulate a datagram and kick it into a TTY queue. */ +static int strip_xmit(struct sk_buff *skb, struct device *dev) +{ + struct strip *strip_info = (struct strip *)(dev->priv); + + if (!dev->start) + { + printk(KERN_ERR "%s: xmit call when iface is down\n", dev->name); + return(1); + } + if (set_bit(0, (void *) &strip_info->dev.tbusy)) return(1); + del_timer(&strip_info->idle_timer); + + /* See if someone has been ifconfigging */ + if (strip_info->mtu != strip_info->dev.mtu) + strip_changedmtu(strip_info); + + strip_send(strip_info, skb); + + if (skb) dev_kfree_skb(skb, FREE_WRITE); + return(0); +} + +/* + * Create the MAC header for an arbitrary protocol layer + * + * saddr!=NULL means use this specific address (n/a for Metricom) + * saddr==NULL means use default device source address + * daddr!=NULL means use this destination address + * daddr==NULL means leave destination address alone + * (e.g. unresolved arp -- kernel will call + * rebuild_header later to fill in the address) + */ + +static int strip_header(struct sk_buff *skb, struct device *dev, + unsigned short type, void *daddr, void *saddr, unsigned len) +{ + STRIP_Header *header = (STRIP_Header *)skb_push(skb, sizeof(STRIP_Header)); + + /*printk(KERN_INFO "%s: strip_header 0x%04X %s\n", dev->name, type, + type == ETH_P_IP ? "IP" : type == ETH_P_ARP ? "ARP" : "");*/ + + memcpy(header->src_addr.c, dev->dev_addr, dev->addr_len); + header->protocol = htons(type); + + /*HexDump("strip_header", (struct strip *)(dev->priv), skb->data, skb->data + skb->len);*/ + + if (!daddr) return(-dev->hard_header_len); + + memcpy(header->dst_addr.c, daddr, dev->addr_len); + return(dev->hard_header_len); +} + +/* + * Rebuild the MAC header. This is called after an ARP + * (or in future other address resolution) has completed on this + * sk_buff. We now let ARP fill in the other fields. + * I think this should return zero if packet is ready to send, + * or non-zero if it needs more time to do an address lookup + */ + +static int strip_rebuild_header(void *buff, struct device *dev, + unsigned long dst, struct sk_buff *skb) +{ + STRIP_Header *header = (STRIP_Header *)buff; + + /*printk(KERN_INFO "%s: strip_rebuild_header\n", dev->name);*/ + +#ifdef CONFIG_INET + /* Arp find returns zero if if knows the address, */ + /* or if it doesn't know the address it sends an ARP packet and returns non-zero */ + return arp_find(header->dst_addr.c, dst, dev, dev->pa_addr, skb)? 1 : 0; +#else + return 0; +#endif +} + +/* + * IdleTask periodically calls strip_xmit, so even when we have no IP packets + * to send for an extended period of time, the watchdog processing still gets + * done to ensure that the radio stays in Starmode + */ + +static void strip_IdleTask(unsigned long parameter) +{ + strip_xmit(NULL, (struct device *)parameter); +} + + +/************************************************************************/ +/* Receiving routines */ + +static int strip_receive_room(struct tty_struct *tty) +{ + return 0x10000; /* We can handle an infinite amount of data. :-) */ +} + +static void get_radio_address(struct strip *strip_info, __u8 *p) +{ + MetricomAddress addr; + + string_to_radio_address(&addr, p); + + /* See if our radio address has changed */ + if (memcmp(strip_info->dev.dev_addr, addr.c, sizeof(addr))) + { + MetricomAddressString addr_string; + radio_address_to_string(&addr, &addr_string); + printk(KERN_INFO "%s: My radio address = %s\n", strip_info->dev.name, addr_string.c); + memcpy(strip_info->dev.dev_addr, addr.c, sizeof(addr)); + /* Give the radio a few seconds to get its head straight, then send an arp */ + strip_info->gratuitous_arp = jiffies + 6 * HZ; + strip_info->arp_interval = 1 * HZ; + } +} + +static void RecvErr(char *msg, struct strip *strip_info) +{ + __u8 *ptr = strip_info->sx_buff; + __u8 *end = strip_info->sx_buff + strip_info->sx_count; + DumpData(msg, strip_info, ptr, end); + strip_info->rx_errors++; +} + +static void RecvErr_Message(struct strip *strip_info, __u8 *sendername, const __u8 *msg) +{ + static const char ERR_001[] = "001"; /* Not in StarMode! */ + static const char ERR_002[] = "002"; /* Remap handle */ + static const char ERR_003[] = "003"; /* Can't resolve name */ + static const char ERR_004[] = "004"; /* Name too small or missing */ + static const char ERR_005[] = "005"; /* Bad count specification */ + static const char ERR_006[] = "006"; /* Header too big */ + static const char ERR_007[] = "007"; /* Body too big */ + static const char ERR_008[] = "008"; /* Bad character in name */ + static const char ERR_009[] = "009"; /* No count or line terminator */ + + if (!strncmp(msg, ERR_001, sizeof(ERR_001)-1)) + { + RecvErr("Error Msg:", strip_info); + printk(KERN_INFO "%s: Radio %s is not in StarMode\n", + strip_info->dev.name, sendername); + } + else if (!strncmp(msg, ERR_002, sizeof(ERR_002)-1)) + { + RecvErr("Error Msg:", strip_info); +#ifdef notyet /*Kernel doesn't have scanf!*/ + int handle; + __u8 newname[64]; + sscanf(msg, "ERR_002 Remap handle &%d to name %s", &handle, newname); + printk(KERN_INFO "%s: Radio name %s is handle %d\n", + strip_info->dev.name, newname, handle); +#endif + } + else if (!strncmp(msg, ERR_003, sizeof(ERR_003)-1)) + { + RecvErr("Error Msg:", strip_info); + printk(KERN_INFO "%s: Destination radio name is unknown\n", + strip_info->dev.name); + } + else if (!strncmp(msg, ERR_004, sizeof(ERR_004)-1)) + { + strip_info->watchdog_doreset = jiffies + LongTime; + if (!strip_info->working) + { + strip_info->working = TRUE; + printk(KERN_INFO "%s: Radio now in starmode\n", + strip_info->dev.name); + /* + * If the radio has just entered a working state, we should do our first + * probe ASAP, so that we find out our radio address etc. without delay. + */ + strip_info->watchdog_doprobe = jiffies; + } + if (!strip_info->structured_messages && sendername) + { + strip_info->structured_messages = TRUE; + printk(KERN_INFO "%s: Radio provides structured messages\n", + strip_info->dev.name); + } + } + else if (!strncmp(msg, ERR_005, sizeof(ERR_005)-1)) + RecvErr("Error Msg:", strip_info); + else if (!strncmp(msg, ERR_006, sizeof(ERR_006)-1)) + RecvErr("Error Msg:", strip_info); + else if (!strncmp(msg, ERR_007, sizeof(ERR_007)-1)) + { + /* + * Note: This error knocks the radio back into + * command mode. + */ + RecvErr("Error Msg:", strip_info); + printk(KERN_ERR "%s: Error! Packet size too big for radio.", + strip_info->dev.name); + strip_info->watchdog_doreset = jiffies; /* Do reset ASAP */ + } + else if (!strncmp(msg, ERR_008, sizeof(ERR_008)-1)) + { + RecvErr("Error Msg:", strip_info); + printk(KERN_ERR "%s: Radio name contains illegal character\n", + strip_info->dev.name); + } + else if (!strncmp(msg, ERR_009, sizeof(ERR_009)-1)) + RecvErr("Error Msg:", strip_info); + else + RecvErr("Error Msg:", strip_info); +} + +static void process_AT_response(struct strip *strip_info, __u8 *ptr, __u8 *end) +{ + static const char ATS305[] = "ATS305?"; + static const char ATS300[] = "ATS300?"; + static const char ATS325[] = "ATS325?"; + static const char ATI2[] = "AT~I2 nn"; + + /* Skip to the first newline character */ + __u8 *p = ptr; + while (p < end && *p != 10) p++; + if (p >= end) return; + p++; + + if (!strncmp(ptr, ATS305, sizeof(ATS305)-1)) + { + if (IS_RADIO_ADDRESS(p)) get_radio_address(strip_info, p); + } + else if (!strncmp(ptr, ATS300, sizeof(ATS300)-1)) { + get_radio_version(strip_info, p, end); + } + else if (!strncmp(ptr, ATS325, sizeof(ATS325)-1)) { + get_radio_voltage(strip_info, p, end); + } + else if (!strncmp(ptr, ATI2, sizeof(ATI2)-1)) { + get_radio_neighbors(strip_info, p, end); + } + else RecvErr("Unknown AT Response:", strip_info); +} + +/* + * Send one completely decapsulated datagram to the next layer. + */ + +static void deliver_packet(struct strip *strip_info, STRIP_Header *header, __u16 packetlen) +{ + struct sk_buff *skb = dev_alloc_skb(sizeof(STRIP_Header) + packetlen); + if (!skb) + { + printk(KERN_INFO "%s: memory squeeze, dropping packet.\n", strip_info->dev.name); + strip_info->rx_dropped++; + } + else + { + memcpy(skb_put(skb, sizeof(STRIP_Header)), header, sizeof(STRIP_Header)); + memcpy(skb_put(skb, packetlen), strip_info->rx_buff, packetlen); + skb->dev = &strip_info->dev; + skb->protocol = header->protocol; + skb->mac.raw = skb->data; + + /* Having put a fake header on the front of the sk_buff for the */ + /* benefit of tools like tcpdump, skb_pull now 'consumes' that */ + /* fake header before we hand the packet up to the next layer. */ + skb_pull(skb, sizeof(STRIP_Header)); + + /* Finally, hand the packet up to the next layer (e.g. IP or ARP, etc.) */ + strip_info->rx_packets++; + netif_rx(skb); + } +} + +static void process_IP_packet(struct strip *strip_info, STRIP_Header *header, __u8 *ptr, __u8 *end) +{ + __u16 packetlen; + +#if DO_PROC_NET_STRIP_TRACE + __u8 *start_ptr = ptr; +#endif DO_PROC_NET_STRIP_TRACE + + /* Decode start of the IP packet header */ + ptr = UnStuffData(ptr, end, strip_info->rx_buff, 4); + if (!ptr) + { + RecvErr("IP Packet too short", strip_info); + return; + } + + packetlen = ((__u16)strip_info->rx_buff[2] << 8) | strip_info->rx_buff[3]; + + if (packetlen > MAX_STRIP_MTU) + { + printk(KERN_ERR "%s: Dropping oversized receive packet: %d bytes\n", + strip_info->dev.name, packetlen); + strip_info->rx_dropped++; + return; + } + + /*printk(KERN_INFO "%s: Got %d byte IP packet\n", strip_info->dev.name, packetlen);*/ + + /* Decode remainder of the IP packet */ + ptr = UnStuffData(ptr, end, strip_info->rx_buff+4, packetlen-4); + if (!ptr) + { + RecvErr("IP Packet too short", strip_info); return; } - - /* No reset. - * If it is time for another tickle, tack it on the end of the packet - */ - if ((long)jiffies - strip_info->watchdog_doprobe >= 0) { - /* printk("%s: Routine radio test.\n", strip_info->dev.name); */ - *ptr++ = '*'; /* Tickle to make radio protest */ - *ptr++ = '*'; - strip_info->tx_left += 2; - strip_info->watchdog_doprobe = jiffies + 10 * HZ; - strip_info->watchdog_doreset = jiffies + 1 * HZ; + + if (ptr < end) + { + RecvErr("IP Packet too long", strip_info); + return; } - - /* All ready. Start the transmission */ - strip_write_some_more(strip_info->tty); + + header->protocol = htons(ETH_P_IP); + +#if DO_PROC_NET_STRIP_TRACE + packet_log(strip_info, strip_info->rx_buff, EntryReceive, header, + packetlen, end-start_ptr, slip_len(strip_info->rx_buff, packetlen)); +#endif DO_PROC_NET_STRIP_TRACE + + deliver_packet(strip_info, header, packetlen); } -/* Encapsulate an IP datagram and kick it into a TTY queue. */ -static int strip_xmit(struct sk_buff *skb, struct device *dev) +static void process_ARP_packet(struct strip *strip_info, STRIP_Header *header, __u8 *ptr, __u8 *end) { - struct strip *strip_info = (struct strip *)(dev->priv); + __u16 packetlen; + struct arphdr *arphdr = (struct arphdr *)strip_info->rx_buff; - if (!dev->start) { - printk("%s: xmit call when iface is down\n", dev->name); - return(1); +#if DO_PROC_NET_STRIP_TRACE + __u8 *start_ptr = ptr; +#endif DO_PROC_NET_STRIP_TRACE + + /* Decode start of the ARP packet */ + ptr = UnStuffData(ptr, end, strip_info->rx_buff, 8); + if (!ptr) + { + RecvErr("ARP Packet too short", strip_info); + return; } - if (set_bit(0, (void *) &strip_info->dev.tbusy)) return(1); - del_timer(&strip_info->idle_timer); - strip_send(strip_info, skb); - if (skb) dev_kfree_skb(skb, FREE_WRITE); - return(0); -} -/* IdleTask periodically calls strip_xmit, so even when we have no IP packets - to send for an extended period of time, the watchdog processing still gets - done to ensure that the radio stays in Starmode */ + packetlen = 8 + (arphdr->ar_hln + arphdr->ar_pln) * 2; -static void strip_IdleTask(unsigned long parameter) -{ - strip_xmit(NULL, (struct device *)parameter); -} + if (packetlen > MAX_STRIP_MTU) + { + printk(KERN_ERR "%s: Dropping oversized receive packet: %d bytes\n", + strip_info->dev.name, packetlen); + strip_info->rx_dropped++; + return; + } -/************************************************************************/ -/* Receiving routines */ + /*printk(KERN_INFO "%s: Got %d byte ARP %s\n", + strip_info->dev.name, packetlen, + ntohs(arphdr->ar_op) == ARPOP_REQUEST ? "request" : "reply");*/ + + /* Decode remainder of the ARP packet */ + ptr = UnStuffData(ptr, end, strip_info->rx_buff+8, packetlen-8); + if (!ptr) + { + RecvErr("ARP Packet too short", strip_info); + return; + } -static int strip_receive_room(struct tty_struct *tty) -{ - return 65536; /* We can handle an infinite amount of data. :-) */ -} + if (ptr < end) + { + RecvErr("ARP Packet too long", strip_info); + return; + } -/* Send one completely decapsulated IP datagram to the IP layer. */ + header->protocol = htons(ETH_P_ARP); -static void strip_bump(struct strip *strip_info, __u16 packetlen) -{ - int count = sizeof(STRIP_Header) + packetlen; - struct sk_buff *skb = dev_alloc_skb(count); - if (skb == NULL) - { - printk("%s: memory squeeze, dropping packet.\n", - strip_info->dev.name); - strip_info->rx_dropped++; - return; - } - skb->dev = &strip_info->dev; - memcpy(skb_put(skb, count), strip_info->rx_buff, count); - skb->mac.raw=skb->data; - skb->protocol = htons(ETH_P_IP); - netif_rx(skb); - strip_info->rx_packets++; -} +#if DO_PROC_NET_STRIP_TRACE + packet_log(strip_info, strip_info->rx_buff, EntryReceive, header, + packetlen, end-start_ptr, slip_len(strip_info->rx_buff, packetlen)); +#endif DO_PROC_NET_STRIP_TRACE -static void RecvErr(char *msg, struct strip *strip_info) -{ - static const int MAX_RecvErr = 80; - __u8 *ptr = strip_info->sx_buff; - __u8 *end = strip_info->sx_buff + strip_info->sx_count; - __u8 pkt_text[MAX_RecvErr], *p = pkt_text; - *p++ = '\"'; - while (ptr= 32 && *ptr <= 126) - *p++ = *ptr; - else - { - sprintf(p, "\\%02X", *ptr); - p+= 3; - } - } - ptr++; - } - if (ptr == end) - *p++ = '\"'; - *p++ = 0; - printk("%-13s%s\n", msg, pkt_text); - set_bit(STR_ERROR, &strip_info->flags); - strip_info->rx_errors++; -} - -static void RecvErr_Message(struct strip *strip_info, __u8 *sendername, __u8 *msg) -{ - static const char ERR_001[] = "ERR_001 Not in StarMode!"; - static const char ERR_002[] = "ERR_002 Remap handle"; - static const char ERR_003[] = "ERR_003 Can't resolve name"; - static const char ERR_004[] = "ERR_004 Name too small or missing"; - static const char ERR_007[] = "ERR_007 Body too big"; - static const char ERR_008[] = "ERR_008 Bad character in name"; - - if (!strncmp(msg, ERR_001, sizeof(ERR_001)-1)) - printk("Radio %s is not in StarMode\n", sendername); - else if (!strncmp(msg, ERR_002, sizeof(ERR_002)-1)) - { -#ifdef notyet /*Kernel doesn't have scanf!*/ - int handle; - __u8 newname[64]; - sscanf(msg, "ERR_002 Remap handle &%d to name %s", &handle, newname); - printk("Radio name %s is handle %d\n", newname, handle); -#endif - } - else if (!strncmp(msg, ERR_003, sizeof(ERR_003)-1)) - printk("Radio name is unknown (\"Can't resolve name\" error)\n"); - else if (!strncmp(msg, ERR_004, sizeof(ERR_004)-1)) - strip_info->watchdog_doreset = jiffies + LONG_TIME; - else if (!strncmp(msg, ERR_007, sizeof(ERR_007)-1)) - { - /* - * Note: This error knocks the radio back into - * command mode. - */ - printk("Error! Packet size is too big for radio."); - strip_info->watchdog_doreset = jiffies; /* Do reset ASAP */ - } - else if (!strncmp(msg, ERR_008, sizeof(ERR_008)-1)) - printk("Name contains illegal character\n"); - else - RecvErr("Error Msg:", strip_info); + deliver_packet(strip_info, header, packetlen); } static void process_packet(struct strip *strip_info) { + STRIP_Header header = { zero_address, zero_address, 0 }; __u8 *ptr = strip_info->sx_buff; __u8 *end = strip_info->sx_buff + strip_info->sx_count; - __u8 *name, *name_end; - __u16 packetlen; + __u8 sendername[32], *sptr = sendername; + MetricomKey key; - /* Ignore empty lines */ - if (strip_info->sx_count == 0) return; + /* Ignore 'OK' responses from prior commands */ + if (strip_info->sx_count == 2 && ptr[0] == 'O' && ptr[1] == 'K') return; - /* Catch 'OK' responses which show radio has fallen out of starmode */ - if (strip_info->sx_count == 2 && ptr[0] == 'O' && ptr[1] == 'K') { - printk("%s: Radio is back in AT command mode: Will Reset\n", - strip_info->dev.name); - strip_info->watchdog_doreset = jiffies; /* Do reset ASAP */ + /* Check for anything that looks like it might be our radio name: dddd-dddd */ + /* (This is here for backwards compatibility with old firmware) */ + if (strip_info->sx_count == 9 && IS_RADIO_ADDRESS(ptr)) + { + get_radio_address(strip_info, ptr); return; } + /*HexDump("Receiving", strip_info, ptr, end);*/ + /* Check for start of address marker, and then skip over it */ - if (*ptr != '*') { + if (*ptr != '*') + { /* Catch other error messages */ if (ptr[0] == 'E' && ptr[1] == 'R' && ptr[2] == 'R' && ptr[3] == '_') - RecvErr_Message(strip_info, NULL, strip_info->sx_buff); + RecvErr_Message(strip_info, NULL, &ptr[4]); else RecvErr("No initial *", strip_info); return; } - ptr++; + ptr++; /* Skip the initial '*' */ - /* Skip the return address */ - name = ptr; - while (ptr < end && *ptr != '*') ptr++; + /* Copy out the return address */ + while (ptr < end && *ptr != '*' && sptr < ARRAY_END(sendername)-1) *sptr++ = *ptr++; + *sptr = 0; /* Null terminate the sender name */ /* Check for end of address marker, and skip over it */ - if (ptr == end) { + if (ptr >= end || *ptr != '*') + { RecvErr("No second *", strip_info); return; } - name_end = ptr++; + ptr++; /* Skip the second '*' */ - /* Check for STRIP key, and skip over it */ - if (ptr[0] != ProtocolKey.c[0] || - ptr[1] != ProtocolKey.c[1] || - ptr[2] != ProtocolKey.c[2] || - ptr[3] != ProtocolKey.c[3]) { - if (ptr[0] == 'E' && ptr[1] == 'R' && ptr[2] == 'R' && ptr[3] == '_') { *name_end = 0; RecvErr_Message(strip_info, name, ptr); } - else RecvErr("Unrecognized protocol key", strip_info); + /* If the sender name is "&COMMAND", ignore this 'packet' */ + /* (This is here for backwards compatibility with old firmware) */ + if (!strcmp(sendername, "&COMMAND")) + { + strip_info->structured_messages = FALSE; return; } - ptr += 4; - /* Decode start of the IP packet header */ - ptr = UnStuffData(ptr, end, strip_info->rx_buff, 4); - if (!ptr) { - RecvErr("Runt packet", strip_info); + if (ptr+4 >= end) + { + RecvErr("No proto key", strip_info); return; } - packetlen = ((__u16)strip_info->rx_buff[2] << 8) | strip_info->rx_buff[3]; -/* printk("Packet %02X.%02X.%02X.%02X\n", - strip_info->rx_buff[0], strip_info->rx_buff[1], - strip_info->rx_buff[2], strip_info->rx_buff[3]); - printk("Got %d byte packet\n", packetlen);*/ - - /* Decode remainder of the IP packer */ - ptr = UnStuffData(ptr, end, strip_info->rx_buff+4, packetlen-4); - if (!ptr) { - RecvErr("Runt packet", strip_info); - return; - } - strip_bump(strip_info, packetlen); + /*printk(KERN_INFO "%s: Got packet from \"%s\".\n", strip_info->dev.name, sendername);*/ - /* This turns out to be a mistake. Taking receipt of a valid packet as - * evidence that the radio is correctly in Starmode (and resetting the - * watchdog_doreset timer) is wrong. It turns out that if the radio is - * in command mode, with character echo on, then the echo of the packet - * you sent coming back looks like a valid packet and fools this test. - * We should only accept the "ERR_004 Name too small or missing" message - * as evidence that the radio is correctly in Starmode. - strip_info->watchdog_doprobe = jiffies + 10 * HZ; - strip_info->watchdog_doreset = jiffies + LONG_TIME; + /* + * Fill in (pseudo) source and destination addresses in the packet. + * We assume that the destination address was our address (the radio does not + * tell us this). If the radio supplies a source address, then we use it. */ + memcpy(&header.dst_addr, strip_info->dev.dev_addr, sizeof(MetricomAddress)); + if (IS_RADIO_ADDRESS(sendername)) string_to_radio_address(&header.src_addr, sendername); + + /* Get the protocol key out of the buffer */ + key.c[0] = *ptr++; + key.c[1] = *ptr++; + key.c[2] = *ptr++; + key.c[3] = *ptr++; + + if (key.l == SIP0Key.l) process_IP_packet(strip_info, &header, ptr, end); + else if (key.l == ARP0Key.l) process_ARP_packet(strip_info, &header, ptr, end); + else if (key.l == ATR_Key.l) process_AT_response(strip_info, ptr, end); + else if (key.l == ERR_Key.l) RecvErr_Message(strip_info, sendername, ptr); + else /* RecvErr("Unrecognized protocol key", strip_info); */ + + /* Note, this "else" block is temporary, until Metricom fix their */ + /* packet corruption bug */ + { + RecvErr("Unrecognized protocol key (retrying)", strip_info); + ptr -= 3; /* Back up and try again */ + key.c[0] = *ptr++; + key.c[1] = *ptr++; + key.c[2] = *ptr++; + key.c[3] = *ptr++; + if (key.l == SIP0Key.l) process_IP_packet(strip_info, &header, ptr, end); + else if (key.l == ARP0Key.l) process_ARP_packet(strip_info, &header, ptr, end); + else if (key.l == ATR_Key.l) process_AT_response(strip_info, ptr, end); + else if (key.l == ERR_Key.l) RecvErr_Message(strip_info, sendername, ptr); + else RecvErr("Unrecognized protocol key", strip_info); + } } /* @@ -917,10 +2220,10 @@ * a block of STRIP data has been received, which can now be decapsulated * and sent on to some IP layer for further processing. */ + static void strip_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) { -/* struct timeval tv;*/ struct strip *strip_info = (struct strip *) tty->disc_data; const unsigned char *end = cp + count; @@ -928,104 +2231,86 @@ return; /* Argh! mtu change time! - costs us the packet part received at the change */ - if (strip_info->mtu != STRIP_ENCAP_SIZE(strip_info->dev.mtu)) + if (strip_info->mtu != strip_info->dev.mtu) strip_changedmtu(strip_info); -/* do_gettimeofday(&tv); - printk("**** strip_receive_buf: %3d bytes at %d.%06d\n", - count, tv.tv_sec % 100, tv.tv_usec);*/ +#if 0 + { + struct timeval tv; + do_gettimeofday(&tv); + printk(KERN_INFO "**** strip_receive_buf: %3d bytes at %d.%06d\n", + count, tv.tv_sec % 100, tv.tv_usec); + } +#endif + /* Read the characters out of the buffer */ - while (cp < end) { - if (fp && *fp++) { - if (!set_bit(STR_ERROR, &strip_info->flags)) strip_info->rx_errors++; - } - else if (*cp == 0x0D) { - /*printk("Cut a %d byte packet (%d bytes remaining)\n", - strip_info->sx_count, end-cp-1);*/ - if (!clear_bit(STR_ERROR, &strip_info->flags)) - process_packet(strip_info); - strip_info->sx_count = 0; + while (cp < end) + { + if (fp && *fp++ && !strip_info->discard) /* If there's a serial error, record it */ + { + strip_info->discard = 1; + strip_info->rx_errors++; } - else if (!test_bit(STR_ERROR, &strip_info->flags) && - (strip_info->sx_count > 0 || *cp != 0x0A)) + + /* Leading control characters (CR, NL, Tab, etc.) are ignored */ + if (strip_info->sx_count > 0 || *cp >= ' ') { - /* (leading newline characters are ignored) */ - if (strip_info->sx_count < strip_info->buffsize) - strip_info->sx_buff[strip_info->sx_count++] = *cp; - else + if (*cp == 0x0D) /* If end of packet, decide what to do with it */ + { + if (strip_info->sx_count > 3000) + printk(KERN_INFO "Cut a %d byte packet (%d bytes remaining)%s\n", + strip_info->sx_count, end-cp-1, + strip_info->discard ? " (discarded)" : ""); + if (strip_info->sx_count > strip_info->sx_size) + { + strip_info->discard = 1; + strip_info->rx_over_errors++; + printk(KERN_INFO "%s: sx_buff overflow (%d bytes total)\n", + strip_info->dev.name, strip_info->sx_count); + } + if (!strip_info->discard) process_packet(strip_info); + strip_info->discard = 0; + strip_info->sx_count = 0; + } + else if (!strip_info->discard) /* If we're not discarding, store the character */ { - set_bit(STR_ERROR, &strip_info->flags); - strip_info->rx_over_errors++; + /* Make sure we have space in the buffer */ + if (strip_info->sx_count < strip_info->sx_size) + strip_info->sx_buff[strip_info->sx_count] = *cp; + strip_info->sx_count++; } } cp++; } } + /************************************************************************/ /* General control routines */ -/* - * Create the Ethernet MAC header for an arbitrary protocol layer - * - * saddr=NULL means use device source address - * daddr=NULL means leave destination address (eg unresolved arp) - */ - -static int strip_header(struct sk_buff *skb, struct device *dev, - unsigned short type, void *daddr, void *saddr, unsigned len) -{ - return(-dev->hard_header_len); -} - -/* - * Rebuild the Ethernet MAC header. This is called after an ARP - * (or in future other address resolution) has completed on this - * sk_buff. We now let ARP fill in the other fields. - */ - -/* I think this should return zero if packet is ready to send, */ -/* or non-zero if it needs more time to do an address lookup */ - -static int strip_rebuild_header(void *buff, struct device *dev, - unsigned long dst, struct sk_buff *skb) -{ -/* STRIP_Header *h = (STRIP_Header *)buff;*/ - -#ifdef CONFIG_INET - /* I'll use arp_find when I understand it */ - /* Arp find returns zero if if knows the address, or if it doesn't */ - /* know the address it sends an ARP packet and returns non-zero */ - /*return arp_find(eth->h_dest, dst, dev, dev->pa_addr, skb)? 1 : 0;*/ - return(0); -#else - return(0); -#endif -} - static int strip_set_dev_mac_address(struct device *dev, void *addr) { - memcpy(dev->dev_addr, addr, 7); - return 0; + return -1; /* You cannot override a Metricom radio's address */ } static struct enet_statistics *strip_get_stats(struct device *dev) { - static struct enet_statistics stats; - struct strip *strip_info = (struct strip *)(dev->priv); + static struct enet_statistics stats; + struct strip *strip_info = (struct strip *)(dev->priv); - memset(&stats, 0, sizeof(struct enet_statistics)); + memset(&stats, 0, sizeof(struct enet_statistics)); - stats.rx_packets = strip_info->rx_packets; - stats.tx_packets = strip_info->tx_packets; - stats.rx_dropped = strip_info->rx_dropped; - stats.tx_dropped = strip_info->tx_dropped; - stats.tx_errors = strip_info->tx_errors; - stats.rx_errors = strip_info->rx_errors; - stats.rx_over_errors = strip_info->rx_over_errors; - return(&stats); + stats.rx_packets = strip_info->rx_packets; + stats.tx_packets = strip_info->tx_packets; + stats.rx_dropped = strip_info->rx_dropped; + stats.tx_dropped = strip_info->tx_dropped; + stats.tx_errors = strip_info->tx_errors; + stats.rx_errors = strip_info->rx_errors; + stats.rx_over_errors = strip_info->rx_over_errors; + return(&stats); } + /************************************************************************/ /* Opening and closing */ @@ -1055,298 +2340,286 @@ static int strip_open_low(struct device *dev) { - struct strip *strip_info = (struct strip *)(dev->priv); - unsigned long len; - - if (strip_info->tty == NULL) - return(-ENODEV); + struct strip *strip_info = (struct strip *)(dev->priv); - /* - * Allocate the STRIP frame buffers: - * - * rbuff Receive buffer. - * tbuff Transmit buffer. - * cbuff Temporary compression buffer. - */ + if (strip_info->tty == NULL) + return(-ENODEV); - len = STRIP_ENCAP_SIZE(dev->mtu); - if (len < STRIP_ENCAP_SIZE(576)) - len = STRIP_ENCAP_SIZE(576); - strip_info->rx_buff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL); - if (strip_info->rx_buff == NULL) - goto norbuff; - strip_info->sx_buff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL); - if (strip_info->sx_buff == NULL) - goto nosbuff; - strip_info->tx_buff = (unsigned char *) kmalloc(len + 4, GFP_KERNEL); - if (strip_info->tx_buff == NULL) - goto notbuff; - - strip_info->flags &= (1 << STR_INUSE); /* Clear ESCAPE & ERROR flags */ - strip_info->mtu = STRIP_ENCAP_SIZE(dev->mtu); - strip_info->buffsize = len; - strip_info->sx_count = 0; - strip_info->tx_left = 0; + if (!allocate_buffers(strip_info)) + return(-ENOMEM); - /* - * Needed because address '0' is special - */ - - if (dev->pa_addr == 0) - dev->pa_addr=ntohl(0xC0A80001); - dev->tbusy = 0; - dev->start = 1; + strip_info->discard = 0; + strip_info->working = FALSE; + strip_info->structured_messages = FALSE; + strip_info->sx_count = 0; + strip_info->tx_left = 0; - printk("%s: Initializing Radio.\n", strip_info->dev.name); - ResetRadio(strip_info); - strip_info->idle_timer.expires = jiffies + 2 * HZ; - add_timer(&strip_info->idle_timer); - return(0); + /* + * Needed because address '0' is special + */ -notbuff: - kfree(strip_info->sx_buff); -nosbuff: - kfree(strip_info->rx_buff); -norbuff: - return(-ENOMEM); + if (dev->pa_addr == 0) + dev->pa_addr=ntohl(0xC0A80001); + dev->tbusy = 0; + dev->start = 1; + + printk(KERN_INFO "%s: Initializing Radio.\n", strip_info->dev.name); + ResetRadio(strip_info); + strip_info->idle_timer.expires = jiffies + 2 * HZ; + add_timer(&strip_info->idle_timer); + return(0); } /* - * Close the low-level part of the STRIP channel. Easy! + * Close the low-level part of the STRIP channel. Easy! */ - + static int strip_close_low(struct device *dev) { - struct strip *strip_info = (struct strip *)(dev->priv); + struct strip *strip_info = (struct strip *)(dev->priv); - if (strip_info->tty == NULL) - return -EBUSY; - strip_info->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); - dev->tbusy = 1; - dev->start = 0; - - /* - * Free all STRIP frame buffers. - */ - if (strip_info->rx_buff) - { - kfree(strip_info->rx_buff); - strip_info->rx_buff = NULL; - } - if (strip_info->sx_buff) - { - kfree(strip_info->sx_buff); - strip_info->sx_buff = NULL; - } - if (strip_info->tx_buff) - { - kfree(strip_info->tx_buff); - strip_info->tx_buff = NULL; - } - del_timer(&strip_info->idle_timer); - return 0; + if (strip_info->tty == NULL) + return -EBUSY; + strip_info->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + dev->tbusy = 1; + dev->start = 0; + + /* + * Free all STRIP frame buffers. + */ + if (strip_info->rx_buff) + { + kfree(strip_info->rx_buff); + strip_info->rx_buff = NULL; + } + if (strip_info->sx_buff) + { + kfree(strip_info->sx_buff); + strip_info->sx_buff = NULL; + } + if (strip_info->tx_buff) + { + kfree(strip_info->tx_buff); + strip_info->tx_buff = NULL; + } + del_timer(&strip_info->idle_timer); + return 0; } -/* - * This routine is called by DDI when the - * (dynamically assigned) device is registered +/* + * This routine is called by DDI when the + * (dynamically assigned) device is registered */ - + static int strip_dev_init(struct device *dev) { - int i; - - /* - * Finish setting up the DEVICE info. - */ + int i; - dev->trans_start = 0; - dev->last_rx = 0; - dev->tx_queue_len = 30; /* Drop after 30 frames queued */ - - dev->flags = 0; - dev->family = AF_INET; - dev->metric = 0; - dev->mtu = STRIP_MTU; - dev->type = ARPHRD_METRICOM; /* dtang */ - dev->hard_header_len = 8; /*sizeof(STRIP_Header);*/ - /* - * dev->priv Already holds a pointer to our struct strip - */ + /* + * Finish setting up the DEVICE info. + */ - dev->broadcast[0] = 0; - dev->dev_addr[0] = 0; - dev->addr_len = sizeof(MetricomAddress); - dev->pa_addr = 0; - dev->pa_brdaddr = 0; - dev->pa_mask = 0; - dev->pa_alen = sizeof(unsigned long); + dev->trans_start = 0; + dev->last_rx = 0; + dev->tx_queue_len = 30; /* Drop after 30 frames queued */ + + dev->flags = 0; + dev->family = AF_INET; + dev->metric = 0; + dev->mtu = DEFAULT_STRIP_MTU; + dev->type = ARPHRD_METRICOM; /* dtang */ + dev->hard_header_len = sizeof(STRIP_Header); + /* + * dev->priv Already holds a pointer to our struct strip + */ - /* - * Pointer to the interface buffers. - */ - - for (i = 0; i < DEV_NUMBUFFS; i++) - skb_queue_head_init(&dev->buffs[i]); + *(MetricomAddress*)&dev->broadcast = broadcast_address; + dev->dev_addr[0] = 0; + dev->addr_len = sizeof(MetricomAddress); + dev->pa_addr = 0; + dev->pa_brdaddr = 0; + dev->pa_mask = 0; + dev->pa_alen = sizeof(unsigned long); - /* - * Pointers to interface service routines. - */ + /* + * Pointer to the interface buffers. + */ - dev->open = strip_open_low; - dev->stop = strip_close_low; - dev->hard_start_xmit = strip_xmit; - dev->hard_header = strip_header; - dev->rebuild_header = strip_rebuild_header; - /* dev->type_trans unused */ - /* dev->set_multicast_list unused */ - dev->set_mac_address = strip_set_dev_mac_address; - /* dev->do_ioctl unused */ - /* dev->set_config unused */ - dev->get_stats = strip_get_stats; - return 0; + for (i = 0; i < DEV_NUMBUFFS; i++) + skb_queue_head_init(&dev->buffs[i]); + + /* + * Pointers to interface service routines. + */ + + dev->open = strip_open_low; + dev->stop = strip_close_low; + dev->hard_start_xmit = strip_xmit; + dev->hard_header = strip_header; + dev->rebuild_header = strip_rebuild_header; + /* dev->type_trans unused */ + /* dev->set_multicast_list unused */ + dev->set_mac_address = strip_set_dev_mac_address; + /* dev->do_ioctl unused */ + /* dev->set_config unused */ + dev->get_stats = strip_get_stats; + return 0; } /* - * Free a STRIP channel. + * Free a STRIP channel. */ - + static void strip_free(struct strip *strip_info) { - *(strip_info->referrer) = strip_info->next; - if (strip_info->next) - strip_info->next->referrer = strip_info->referrer; - strip_info->magic = 0; - kfree(strip_info); + MetricomNode *node, *free; + + *(strip_info->referrer) = strip_info->next; + if (strip_info->next) + strip_info->next->referrer = strip_info->referrer; + strip_info->magic = 0; + + for (node = strip_info->neighbor_list; node != NULL; ) + { + free = node; + node = node->next; + kfree(free); + } + kfree(strip_info); } -/* - * Allocate a new free STRIP channel +/* + * Allocate a new free STRIP channel */ - + static struct strip *strip_alloc(void) { - int channel_id = 0; - struct strip **s = &struct_strip_list; - struct strip *strip_info = (struct strip *) - kmalloc(sizeof(struct strip), GFP_KERNEL); + int channel_id = 0; + struct strip **s = &struct_strip_list; + struct strip *strip_info = (struct strip *) + kmalloc(sizeof(struct strip), GFP_KERNEL); - if (!strip_info) - return(NULL); /* If no more memory, return */ + if (!strip_info) + return(NULL); /* If no more memory, return */ - /* - * Clear the allocated memory - */ - - memset(strip_info, 0, sizeof(struct strip)); + /* + * Clear the allocated memory + */ - /* - * Search the list to find where to put our new entry - * (and in the process decide what channel number it is - * going to be) - */ - - while (*s && (*s)->dev.base_addr == channel_id) - { - channel_id++; - s = &(*s)->next; - } + memset(strip_info, 0, sizeof(struct strip)); - /* - * Fill in the link pointers - */ - - strip_info->next = *s; - if (*s) - (*s)->referrer = &strip_info->next; - strip_info->referrer = s; - *s = strip_info; - - set_bit(STR_INUSE, &strip_info->flags); - strip_info->magic = STRIP_MAGIC; - strip_info->tty = NULL; - - init_timer(&strip_info->idle_timer); - strip_info->idle_timer.data = (long)&strip_info->dev; - strip_info->idle_timer.function = strip_IdleTask; - - sprintf(strip_info->if_name, "st%d", channel_id); - strip_info->dev.name = strip_info->if_name; - strip_info->dev.base_addr = channel_id; - strip_info->dev.priv = (void*)strip_info; - strip_info->dev.next = NULL; - strip_info->dev.init = strip_dev_init; - - return(strip_info); + /* + * Search the list to find where to put our new entry + * (and in the process decide what channel number it is + * going to be) + */ + + while (*s && (*s)->dev.base_addr == channel_id) + { + channel_id++; + s = &(*s)->next; + } + + /* + * Fill in the link pointers + */ + + strip_info->next = *s; + if (*s) + (*s)->referrer = &strip_info->next; + strip_info->referrer = s; + *s = strip_info; + + strip_info->magic = STRIP_MAGIC; + strip_info->tty = NULL; + + strip_info->gratuitous_arp = jiffies + LongTime; + strip_info->arp_interval = 0; + init_timer(&strip_info->idle_timer); + strip_info->idle_timer.data = (long)&strip_info->dev; + strip_info->idle_timer.function = strip_IdleTask; + + strip_info->neighbor_list = kmalloc(sizeof(MetricomNode), GFP_KERNEL); + strip_info->neighbor_list->type = 0; + strip_info->neighbor_list->next = NULL; + + /* Note: strip_info->if_name is currently 8 characters long */ + sprintf(strip_info->if_name, "st%d", channel_id); + strip_info->dev.name = strip_info->if_name; + strip_info->dev.base_addr = channel_id; + strip_info->dev.priv = (void*)strip_info; + strip_info->dev.next = NULL; + strip_info->dev.init = strip_dev_init; + + return(strip_info); } /* - * Open the high-level part of the STRIP channel. - * This function is called by the TTY module when the - * STRIP line discipline is called for. Because we are - * sure the tty line exists, we only have to link it to - * a free STRIP channel... + * Open the high-level part of the STRIP channel. + * This function is called by the TTY module when the + * STRIP line discipline is called for. Because we are + * sure the tty line exists, we only have to link it to + * a free STRIP channel... */ static int strip_open(struct tty_struct *tty) { - struct strip *strip_info = (struct strip *) tty->disc_data; + struct strip *strip_info = (struct strip *) tty->disc_data; - /* - * First make sure we're not already connected. - */ - - if (strip_info && strip_info->magic == STRIP_MAGIC) - return -EEXIST; + /* + * First make sure we're not already connected. + */ - /* - * OK. Find a free STRIP channel to use. - */ - - if ((strip_info = strip_alloc()) == NULL) - return -ENFILE; + if (strip_info && strip_info->magic == STRIP_MAGIC) + return -EEXIST; - /* - * Register our newly created device so it can be ifconfig'd - * strip_dev_init() will be called as a side-effect - */ - - if (register_netdev(&strip_info->dev) != 0) - { - printk("strip: register_netdev() failed.\n"); - strip_free(strip_info); - return -ENFILE; - } + /* + * OK. Find a free STRIP channel to use. + */ + if ((strip_info = strip_alloc()) == NULL) + return -ENFILE; - strip_info->tty = tty; - tty->disc_data = strip_info; - if (tty->driver.flush_buffer) - tty->driver.flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); + /* + * Register our newly created device so it can be ifconfig'd + * strip_dev_init() will be called as a side-effect + */ - /* - * Restore default settings - */ - - strip_info->dev.type = ARPHRD_METRICOM; /* dtang */ + if (register_netdev(&strip_info->dev) != 0) + { + printk(KERN_ERR "strip: register_netdev() failed.\n"); + strip_free(strip_info); + return -ENFILE; + } - /* - * Set tty options - */ + strip_info->tty = tty; + tty->disc_data = strip_info; + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + + /* + * Restore default settings + */ - tty->termios->c_iflag |= IGNBRK |IGNPAR;/* Ignore breaks and parity errors. */ - tty->termios->c_cflag |= CLOCAL; /* Ignore modem control signals. */ - tty->termios->c_cflag &= ~HUPCL; /* Don't close on hup */ + strip_info->dev.type = ARPHRD_METRICOM; /* dtang */ + + /* + * Set tty options + */ + + tty->termios->c_iflag |= IGNBRK |IGNPAR;/* Ignore breaks and parity errors. */ + tty->termios->c_cflag |= CLOCAL; /* Ignore modem control signals. */ + tty->termios->c_cflag &= ~HUPCL; /* Don't close on hup */ #ifdef MODULE - MOD_INC_USE_COUNT; + MOD_INC_USE_COUNT; #endif - /* - * Done. We have linked the TTY line to a channel. - */ - return(strip_info->dev.base_addr); + /* + * Done. We have linked the TTY line to a channel. + */ + return(strip_info->dev.base_addr); } /* @@ -1355,80 +2628,108 @@ * TTY line discipline to what it was before it got hooked to STRIP * (which usually is TTY again). */ + static void strip_close(struct tty_struct *tty) { - struct strip *strip_info = (struct strip *) tty->disc_data; + struct strip *strip_info = (struct strip *) tty->disc_data; - /* - * First make sure we're connected. - */ - - if (!strip_info || strip_info->magic != STRIP_MAGIC) - return; + /* + * First make sure we're connected. + */ - dev_close(&strip_info->dev); - unregister_netdev(&strip_info->dev); - - tty->disc_data = 0; - strip_info->tty = NULL; - strip_free(strip_info); - tty->disc_data = NULL; + if (!strip_info || strip_info->magic != STRIP_MAGIC) + return; + + dev_close(&strip_info->dev); + unregister_netdev(&strip_info->dev); + + tty->disc_data = 0; + strip_info->tty = NULL; + strip_free(strip_info); + tty->disc_data = NULL; #ifdef MODULE - MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; #endif } /************************************************************************/ -/* Perform I/O control calls on an active STRIP channel. */ +/* Perform I/O control calls on an active STRIP channel. */ -static int strip_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) +static int strip_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) { - struct strip *strip_info = (struct strip *) tty->disc_data; - int err; + struct strip *strip_info = (struct strip *) tty->disc_data; + int err; - /* - * First make sure we're connected. - */ - - if (!strip_info || strip_info->magic != STRIP_MAGIC) - return -EINVAL; - - switch(cmd) - { - case SIOCGIFNAME: - err = verify_area(VERIFY_WRITE, (void*)arg, 16); - if (err) - return -err; - memcpy_tofs((void*)arg, strip_info->dev.name, - strlen(strip_info->dev.name) + 1); - return 0; - - case SIOCSIFHWADDR: - return -EINVAL; - - /* - * Allow stty to read, but not set, the serial port - */ - - case TCGETS: - case TCGETA: - return n_tty_ioctl(tty, (struct file *) file, cmd, - (unsigned long) arg); + /* + * First make sure we're connected. + */ - default: - return -ENOIOCTLCMD; - } + if (!strip_info || strip_info->magic != STRIP_MAGIC) + return -EINVAL; + + switch(cmd) + { + case SIOCGIFNAME: + err = verify_area(VERIFY_WRITE, (void*)arg, 16); + if (err) + return -err; + memcpy_tofs((void*)arg, strip_info->dev.name, + strlen(strip_info->dev.name) + 1); + return 0; + + case SIOCSIFHWADDR: + return -EINVAL; + + /* + * Allow stty to read, but not set, the serial port + */ + + case TCGETS: + case TCGETA: + return n_tty_ioctl(tty, (struct file *) file, cmd, + (unsigned long) arg); + + default: + return -ENOIOCTLCMD; + } } + /************************************************************************/ /* Initialization */ /* - * Initialize the STRIP driver. - * This routine is called at boot time, to bootstrap the multi-channel - * STRIP driver + * Registers with the /proc file system to create different /proc/net files. + */ + +static int strip_proc_net_register(unsigned short type, char *file_name, + int (*get_info)(char *, char **, off_t, int, int)) +{ + struct proc_dir_entry *strip_entry; + + strip_entry = kmalloc(sizeof(struct proc_dir_entry), GFP_ATOMIC); + + memset(strip_entry, 0, sizeof(struct proc_dir_entry)); + strip_entry->low_ino = type; + strip_entry->namelen = strlen(file_name); + strip_entry->name = file_name; + strip_entry->mode = S_IFREG | S_IRUGO; + strip_entry->nlink = 1; + strip_entry->uid = 0; + strip_entry->gid = 0; + strip_entry->size = 0; + strip_entry->ops = &proc_net_inode_operations; + strip_entry->get_info = get_info; + + return proc_net_register(strip_entry); +} + +/* + * Initialize the STRIP driver. + * This routine is called at boot time, to bootstrap the multi-channel + * STRIP driver */ #ifdef MODULE @@ -1436,44 +2737,67 @@ #endif int strip_init_ctrl_dev(struct device *dummy) { - static struct tty_ldisc strip_ldisc; - int status; - printk("STRIP: version %s (unlimited channels)\n", STRIP_VERSION); + static struct tty_ldisc strip_ldisc; + int status; - /* - * Fill in our line protocol discipline, and register it - */ - - memset(&strip_ldisc, 0, sizeof(strip_ldisc)); - strip_ldisc.magic = TTY_LDISC_MAGIC; - strip_ldisc.flags = 0; - strip_ldisc.open = strip_open; - strip_ldisc.close = strip_close; - strip_ldisc.read = NULL; - strip_ldisc.write = NULL; - strip_ldisc.ioctl = strip_ioctl; - strip_ldisc.select = NULL; - strip_ldisc.receive_buf = strip_receive_buf; - strip_ldisc.receive_room = strip_receive_room; - strip_ldisc.write_wakeup = strip_write_some_more; - status = tty_register_ldisc(N_STRIP, &strip_ldisc); - if (status != 0) - { - printk("STRIP: can't register line discipline (err = %d)\n", status); - } + printk("STRIP: version %s (unlimited channels)\n", StripVersion); + + /* + * Fill in our line protocol discipline, and register it + */ + + memset(&strip_ldisc, 0, sizeof(strip_ldisc)); + strip_ldisc.magic = TTY_LDISC_MAGIC; + strip_ldisc.flags = 0; + strip_ldisc.open = strip_open; + strip_ldisc.close = strip_close; + strip_ldisc.read = NULL; + strip_ldisc.write = NULL; + strip_ldisc.ioctl = strip_ioctl; + strip_ldisc.select = NULL; + strip_ldisc.receive_buf = strip_receive_buf; + strip_ldisc.receive_room = strip_receive_room; + strip_ldisc.write_wakeup = strip_write_some_more; + status = tty_register_ldisc(N_STRIP, &strip_ldisc); + if (status != 0) + { + printk(KERN_ERR "STRIP: can't register line discipline (err = %d)\n", status); + } + + /* + * Register the status and trace files with /proc + */ + +#if DO_PROC_NET_STRIP_STATUS + if (strip_proc_net_register(PROC_NET_STRIP_STATUS, "strip_status", + &strip_get_status_info) != 0) + { + printk(KERN_ERR "strip: status strip_proc_net_register() failed.\n"); + } +#endif + +#if DO_PROC_NET_STRIP_TRACE + if (strip_proc_net_register(PROC_NET_STRIP_TRACE, "strip_trace", + &strip_get_trace_info) != 0) + { + printk(KERN_ERR "strip: trace strip_proc_net_register() failed.\n"); + } +#endif #ifdef MODULE - return status; + return status; #else - /* Return "not found", so that dev_init() will unlink - * the placeholder device entry for us. - */ - return ENODEV; + + /* Return "not found", so that dev_init() will unlink + * the placeholder device entry for us. + */ + return ENODEV; #endif } + /************************************************************************/ -/* From here down is only used when compiled as an external module */ +/* From here down is only used when compiled as an external module */ #ifdef MODULE @@ -1484,11 +2808,20 @@ void cleanup_module(void) { - int i; - while (struct_strip_list) - strip_free(struct_strip_list); + int i; + while (struct_strip_list) + strip_free(struct_strip_list); + + /* Unregister with the /proc/net files here. */ + +#if DO_PROC_NET_STRIP_TRACE + proc_net_unregister(PROC_NET_STRIP_TRACE); +#endif +#if DO_PROC_NET_STRIP_STATUS + proc_net_unregister(PROC_NET_STRIP_STATUS); +#endif - if ((i = tty_register_ldisc(N_STRIP, NULL))) - printk("STRIP: can't unregister line discipline (err = %d)\n", i); + if ((i = tty_register_ldisc(N_STRIP, NULL))) + printk(KERN_ERR "STRIP: can't unregister line discipline (err = %d)\n", i); } #endif /* MODULE */ diff -ur --new-file old/linux/drivers/net/wavelan.c new/linux/drivers/net/wavelan.c --- old/linux/drivers/net/wavelan.c Mon Mar 4 08:16:36 1996 +++ new/linux/drivers/net/wavelan.c Sat Aug 17 20:02:01 1996 @@ -69,7 +69,7 @@ extern int wavelan_probe(device *); /* See Space.c */ -static const char *version = "wavelan.c:v7 95/4/8\n"; +static const char *version = "wavelan.c:v8 96/8/18\n"; /* * Entry point forward declarations. @@ -786,6 +786,13 @@ #endif /* 0 */ 0x390, }; + static struct proc_dir_entry pe = + { + PROC_NET_WAVELAN, 7, "wavelan", + S_IFREG | S_IRUGO, 1, 0, 0, + 0, &proc_net_inode_operations, + wavelan_get_info + }; if (wavelan_debug > 0) printk("%s: ->wavelan_probe(dev=0x%x (base_addr=0x%x))\n", dev->name, (unsigned int)dev, (unsigned int)dev->base_addr); @@ -822,6 +829,8 @@ r = wavelan_probe1(dev, base_addr); if (wavelan_debug > 0) printk("%s: <-wavelan_probe(): %d\n", dev->name, r); + if (r == 0) + proc_net_register(&pe); return r; } @@ -834,13 +843,7 @@ { if (wavelan_debug > 0) printk("%s: <-wavelan_probe(): 0\n", dev->name); - proc_net_register(&(struct proc_dir_entry) { - PROC_NET_WAVELAN, 7, "wavelan", - S_IFREG | S_IRUGO, 1, 0, 0, - 0, &proc_net_inode_operations, - wavelan_get_info - }); - + proc_net_register(&pe); return 0; } } @@ -2495,6 +2498,7 @@ * Marc Meertens (Marc.Meertens@Utrecht.NCR.com), * Pauline Middelink (middelin@polyware.iaf.nl), * Robert Morris (rtm@das.harvard.edu), + * Jean Tourrilhes (jt@hplb.hpl.hp.com), * Girish Welling (welling@paul.rutgers.edu), * * Thanks go also to: @@ -2517,6 +2521,6 @@ * Please send bug reports, updates, comments to: * * Bruce Janson Email: bruce@cs.usyd.edu.au - * Basser Department of Computer Science Phone: +61-2-351-3423 - * University of Sydney, N.S.W., 2006, AUSTRALIA Fax: +61-2-351-3838 + * Basser Department of Computer Science Phone: +61-2-9351-3423 + * University of Sydney, N.S.W., 2006, AUSTRALIA Fax: +61-2-9351-3838 */ diff -ur --new-file old/linux/drivers/net/wic.c new/linux/drivers/net/wic.c --- old/linux/drivers/net/wic.c Thu Apr 18 13:35:33 1996 +++ new/linux/drivers/net/wic.c Tue Jul 2 18:08:42 1996 @@ -49,7 +49,7 @@ #include #include #include -#include +#include #define NET_DEBUG 1 /* Use 0 for production, 1 for verification, >2 for debug */ diff -ur --new-file old/linux/drivers/pci/pci.c new/linux/drivers/pci/pci.c --- old/linux/drivers/pci/pci.c Mon May 27 13:01:04 1996 +++ new/linux/drivers/pci/pci.c Sat Aug 17 20:03:34 1996 @@ -111,9 +111,9 @@ DEVICE( OPTI, OPTI_82C822, "82C822"), DEVICE( SGS, SGS_2000, "STG 2000X"), DEVICE( SGS, SGS_1764, "STG 1764X"), - DEVICE( BUSLOGIC, BUSLOGIC_946C_2,"BT-946C"), - DEVICE( BUSLOGIC, BUSLOGIC_946C, "BT-946C"), - DEVICE( BUSLOGIC, BUSLOGIC_930, "BT-930"), + DEVICE( BUSLOGIC, BUSLOGIC_MULTIMASTER_NC, "MultiMaster NC"), + DEVICE( BUSLOGIC, BUSLOGIC_MULTIMASTER, "MultiMaster"), + DEVICE( BUSLOGIC, BUSLOGIC_FLASHPOINT, "FlashPoint"), DEVICE( OAK, OAK_OTI107, "OTI107"), DEVICE( PROMISE, PROMISE_5300, "DC5030"), DEVICE( N9, N9_I128, "Imagine 128"), @@ -205,7 +205,9 @@ DEVICE( CYCLADES, CYCLOM_Z_Hi, "Cyclom-Z above 1Mbyte"), DEVICE( SYMPHONY, SYMPHONY_101, "82C101"), DEVICE( TEKRAM, TEKRAM_DC290, "DC-290"), + DEVICE( 3DLABS, 3DLABS_300SX, "GLINT 300SX"), DEVICE( AVANCE, AVANCE_2302, "ALG-2302"), + DEVICE( S3, S3_ViRGE, "ViRGE"), DEVICE( S3, S3_811, "Trio32/Trio64"), DEVICE( S3, S3_868, "Vision 868"), DEVICE( S3, S3_928, "Vision 928-P"), @@ -226,12 +228,14 @@ DEVICE( INTEL, INTEL_82437, "82437"), DEVICE( INTEL, INTEL_82371_0, "82371 Triton PIIX"), DEVICE( INTEL, INTEL_82371_1, "82371 Triton PIIX"), + DEVICE( INTEL, INTEL_82441, "82441FX Natoma"), DEVICE( INTEL, INTEL_82439, "82439HX Triton II"), - DEVICE( INTEL, INTEL_82371SB_0,"82371SB Triton II PIIX"), - DEVICE( INTEL, INTEL_82371SB_1,"82371SB Triton II PIIX"), + DEVICE( INTEL, INTEL_82371SB_0,"82371SB Natoma/Triton II PIIX"), + DEVICE( INTEL, INTEL_82371SB_1,"82371SB Natoma/Triton II PIIX"), DEVICE( INTEL, INTEL_P6, "Orion P6"), DEVICE( ADAPTEC, ADAPTEC_7850, "AIC-7850"), DEVICE( ADAPTEC, ADAPTEC_7855, "AIC-7855"), + DEVICE( ADAPTEC, ADAPTEC_7860, "AIC-7860"), DEVICE( ADAPTEC, ADAPTEC_7870, "AIC-7870"), DEVICE( ADAPTEC, ADAPTEC_7871, "AIC-7871"), DEVICE( ADAPTEC, ADAPTEC_7872, "AIC-7872"), @@ -507,6 +511,7 @@ case PCI_VENDOR_ID_CYCLADES: return "Cyclades"; case PCI_VENDOR_ID_SYMPHONY: return "Symphony"; case PCI_VENDOR_ID_TEKRAM: return "Tekram"; + case PCI_VENDOR_ID_3DLABS: return "3Dlabs"; case PCI_VENDOR_ID_AVANCE: return "Avance"; case PCI_VENDOR_ID_S3: return "S3 Inc."; case PCI_VENDOR_ID_INTEL: return "Intel"; diff -ur --new-file old/linux/drivers/scsi/53c7,8xx.c new/linux/drivers/scsi/53c7,8xx.c --- old/linux/drivers/scsi/53c7,8xx.c Tue Jun 4 05:06:37 1996 +++ new/linux/drivers/scsi/53c7,8xx.c Tue Jul 16 11:02:42 1996 @@ -3546,6 +3546,7 @@ case MODE_SELECT: case WRITE_6: case WRITE_10: + case START_STOP: /* also SCAN, which may do DATA OUT */ #if 0 printk("scsi%d : command is ", host->host_no); print_command(cmd->cmnd); @@ -3564,7 +3565,6 @@ * These commands do no data transfer, we should force an * interrupt if a data phase is attempted on them. */ - case START_STOP: case TEST_UNIT_READY: datain = dataout = 0; break; diff -ur --new-file old/linux/drivers/scsi/BusLogic.c new/linux/drivers/scsi/BusLogic.c --- old/linux/drivers/scsi/BusLogic.c Thu Jun 6 01:54:14 1996 +++ new/linux/drivers/scsi/BusLogic.c Wed Jul 17 20:22:13 1996 @@ -24,8 +24,8 @@ */ -#define BusLogic_DriverVersion "2.0.4" -#define BusLogic_DriverDate "5 June 1996" +#define BusLogic_DriverVersion "2.0.6" +#define BusLogic_DriverDate "17 July 1996" #include @@ -162,7 +162,7 @@ /* - BusLogic_DriverInfo returns the Board Name to identify this SCSI Driver + BusLogic_DriverInfo returns the Controller Name to identify this SCSI Driver and Host Adapter. */ @@ -170,7 +170,7 @@ { BusLogic_HostAdapter_T *HostAdapter = (BusLogic_HostAdapter_T *) Host->hostdata; - return HostAdapter->BoardName; + return HostAdapter->ControllerName; } @@ -387,12 +387,12 @@ the Host Adapter (including any discarded data); on failure, it returns -1 if the command was invalid, or -2 if a timeout occurred. - This function is only called during board detection and initialization, so - performance and latency are not critical, and exclusive access to the Host - Adapter hardware is assumed. Once the board and driver are initialized, the - only Host Adapter command that is issued is the single byte Execute Mailbox - Command operation code , which does not require waiting for the Host Adapter - Ready bit to be set in the Status Register. + This function is only called during controller detection and initialization, + so performance and latency are not critical, and exclusive access to the Host + Adapter hardware is assumed. Once the controller and driver are initialized, + the only Host Adapter command that is issued is the single byte Execute + Mailbox Command operation code, which does not require waiting for the Host + Adapter Ready bit to be set in the Status Register. */ static int BusLogic_Command(BusLogic_HostAdapter_T *HostAdapter, @@ -478,7 +478,7 @@ { case BusLogic_InquireInstalledDevicesID0to7: case BusLogic_InquireInstalledDevicesID8to15: - case BusLogic_InquireDevices: + case BusLogic_InquireTargetDevices: /* Approximately 60 seconds. */ TimeoutCounter = loops_per_sec << 2; break; @@ -601,8 +601,8 @@ VendorID == PCI_VENDOR_ID_BUSLOGIC && pcibios_read_config_word(Bus, DeviceFunction, PCI_DEVICE_ID, &DeviceID) == 0 && - (DeviceID == PCI_DEVICE_ID_BUSLOGIC_946C || - DeviceID == PCI_DEVICE_ID_BUSLOGIC_946C_2) && + (DeviceID == PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER || + DeviceID == PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC) && pcibios_read_config_dword(Bus, DeviceFunction, PCI_BASE_ADDRESS_0, &BaseAddress0) == 0 && (BaseAddress0 & PCI_BASE_ADDRESS_SPACE) == @@ -737,10 +737,10 @@ rejected later when the Inquire Extended Setup Information command is issued in BusLogic_CheckHostAdapter. The AMI FastDisk Host Adapter is a BusLogic clone that implements the same interface as earlier BusLogic - boards, including the undocumented commands, and is therefore supported by - this driver. However, the AMI FastDisk always returns 0x00 upon reading - the Geometry Register, so the extended translation option should always be - left disabled on the AMI FastDisk. + controllers, including the undocumented commands, and is therefore + supported by this driver. However, the AMI FastDisk always returns 0x00 + upon reading the Geometry Register, so the extended translation option + should always be left disabled on the AMI FastDisk. */ GeometryRegister = BusLogic_ReadGeometryRegister(HostAdapter); if (TraceProbe) @@ -889,7 +889,7 @@ BusLogic_Configuration_T Configuration; BusLogic_SetupInformation_T SetupInformation; BusLogic_ExtendedSetupInformation_T ExtendedSetupInformation; - BusLogic_BoardModelNumber_T BoardModelNumber; + BusLogic_ControllerModelNumber_T ControllerModelNumber; BusLogic_FirmwareVersion3rdDigit_T FirmwareVersion3rdDigit; BusLogic_FirmwareVersionLetter_T FirmwareVersionLetter; BusLogic_GenericIOPortInformation_T GenericIOPortInformation; @@ -934,27 +934,36 @@ != sizeof(ExtendedSetupInformation)) return BusLogic_Failure(HostAdapter, "INQUIRE EXTENDED SETUP INFORMATION"); /* - Issue the Inquire Board Model Number command. + Issue the Inquire Controller Model Number command. */ - if (!(BoardID.FirmwareVersion1stDigit == '2' && - ExtendedSetupInformation.BusType == 'A')) + if (ExtendedSetupInformation.BusType == 'A' && + BoardID.FirmwareVersion1stDigit == '2') + /* BusLogic BT-542B ISA 2.xx */ + strcpy(ControllerModelNumber, "542B"); + else if (ExtendedSetupInformation.BusType == 'E' && + BoardID.FirmwareVersion1stDigit == '0') + /* AMI FastDisk EISA Series 441 0.x */ + strcpy(ControllerModelNumber, "747A"); + else { - RequestedReplyLength = sizeof(BoardModelNumber); - if (BusLogic_Command(HostAdapter, BusLogic_InquireBoardModelNumber, + RequestedReplyLength = sizeof(ControllerModelNumber); + if (BusLogic_Command(HostAdapter, BusLogic_InquireControllerModelNumber, &RequestedReplyLength, sizeof(RequestedReplyLength), - &BoardModelNumber, sizeof(BoardModelNumber)) - != sizeof(BoardModelNumber)) - return BusLogic_Failure(HostAdapter, "INQUIRE BOARD MODEL NUMBER"); + &ControllerModelNumber, + sizeof(ControllerModelNumber)) + != sizeof(ControllerModelNumber)) + return BusLogic_Failure(HostAdapter, "INQUIRE CONTROLLER MODEL NUMBER"); } - else strcpy(BoardModelNumber, "542B"); /* Issue the Inquire Firmware Version 3rd Digit command. */ - if (BusLogic_Command(HostAdapter, BusLogic_InquireFirmwareVersion3rdDigit, - NULL, 0, &FirmwareVersion3rdDigit, - sizeof(FirmwareVersion3rdDigit)) - != sizeof(FirmwareVersion3rdDigit)) - return BusLogic_Failure(HostAdapter, "INQUIRE FIRMWARE 3RD DIGIT"); + FirmwareVersion3rdDigit = '\0'; + if (BoardID.FirmwareVersion1stDigit > '0') + if (BusLogic_Command(HostAdapter, BusLogic_InquireFirmwareVersion3rdDigit, + NULL, 0, &FirmwareVersion3rdDigit, + sizeof(FirmwareVersion3rdDigit)) + != sizeof(FirmwareVersion3rdDigit)) + return BusLogic_Failure(HostAdapter, "INQUIRE FIRMWARE 3RD DIGIT"); /* BusLogic Host Adapters can be identified by their model number and the major version number of their firmware as follows: @@ -971,22 +980,22 @@ 0.xx AMI FastDisk VLB/EISA BusLogic Clone Host Adapter */ /* - Save the Model Name and Board Name in the Host Adapter structure. + Save the Model Name and Controller Name in the Host Adapter structure. */ TargetPointer = HostAdapter->ModelName; *TargetPointer++ = 'B'; *TargetPointer++ = 'T'; *TargetPointer++ = '-'; - for (i = 0; i < sizeof(BoardModelNumber); i++) + for (i = 0; i < sizeof(ControllerModelNumber); i++) { - Character = BoardModelNumber[i]; + Character = ControllerModelNumber[i]; if (Character == ' ' || Character == '\0') break; *TargetPointer++ = Character; } *TargetPointer++ = '\0'; - strcpy(HostAdapter->BoardName, "BusLogic "); - strcat(HostAdapter->BoardName, HostAdapter->ModelName); - strcpy(HostAdapter->InterruptLabel, HostAdapter->BoardName); + strcpy(HostAdapter->ControllerName, "BusLogic "); + strcat(HostAdapter->ControllerName, HostAdapter->ModelName); + strcpy(HostAdapter->InterruptLabel, HostAdapter->ControllerName); /* Save the Firmware Version in the Host Adapter structure. */ @@ -1133,8 +1142,8 @@ /* Save the Disconnect/Reconnect Permitted flag bits in the Host Adapter structure. The Disconnect Permitted information is only valid on "W" and - "C" Series boards, but Disconnect/Reconnect is always permitted on "S" and - "A" Series boards. + "C" Series controllers, but Disconnect/Reconnect is always permitted on "S" + and "A" Series controllers. */ if (HostAdapter->FirmwareVersion[0] >= '4') HostAdapter->DisconnectPermitted = @@ -1161,6 +1170,13 @@ ExtendedSetupInformation.HostAutomaticConfiguration; HostAdapter->HostUltraSCSI = ExtendedSetupInformation.HostUltraSCSI; /* + Determine whether 64 LUN Format CCBs are supported and save the information + in the Host Adapter structure. + */ + if (HostAdapter->FirmwareVersion[0] == '5' || + (HostAdapter->FirmwareVersion[0] == '4' && HostAdapter->HostWideSCSI)) + HostAdapter->Host64LUNSupport = true; + /* Determine the Host Adapter BIOS Address if the BIOS is enabled and save it in the Host Adapter structure. The BIOS is disabled if the BIOS_Address is 0. @@ -1172,12 +1188,12 @@ if (HostAdapter->BusType == BusLogic_ISA_Bus && high_memory > MAX_DMA_ADDRESS) HostAdapter->BounceBuffersRequired = true; /* - BusLogic BT-445S Host Adapters prior to board revision E have a hardware - bug whereby when the BIOS is enabled, transfers to/from the same address - range the BIOS occupies modulo 16MB are handled incorrectly. Only properly - functioning BT-445S boards have firmware version 3.37, so we require that - ISA Bounce Buffers be used for the buggy BT-445S models if there is more - than 16MB memory. + BusLogic BT-445S Host Adapters prior to controller revision E have a + hardware bug whereby when the BIOS is enabled, transfers to/from the same + address range the BIOS occupies modulo 16MB are handled incorrectly. Only + properly functioning BT-445S controllers have firmware version 3.37, so we + require that ISA Bounce Buffers be used for the buggy BT-445S models if + there is more than 16MB memory. */ if (HostAdapter->BIOS_Address > 0 && strcmp(HostAdapter->ModelName, "BT-445S") == 0 && @@ -1188,16 +1204,8 @@ Determine the maximum number of Target IDs and Logical Units supported by this driver for Wide and Narrow Host Adapters. */ - if (HostAdapter->HostWideSCSI) - { - HostAdapter->MaxTargetDevices = 16; - HostAdapter->MaxLogicalUnits = 64; - } - else - { - HostAdapter->MaxTargetDevices = 8; - HostAdapter->MaxLogicalUnits = 8; - } + HostAdapter->MaxTargetDevices = (HostAdapter->HostWideSCSI ? 16 : 8); + HostAdapter->MaxLogicalUnits = (HostAdapter->Host64LUNSupport ? 64 : 8); /* Select appropriate values for the Mailbox Count, Initial CCBs, and Incremental CCBs variables based on whether or not Strict Round Robin Mode @@ -1223,14 +1231,14 @@ */ if (strcmp(HostAdapter->FirmwareVersion, "3.31") >= 0) { - HostAdapter->StrictRoundRobinModeSupported = true; + HostAdapter->StrictRoundRobinModeSupport = true; HostAdapter->MailboxCount = 255; HostAdapter->InitialCCBs = 64; HostAdapter->IncrementalCCBs = 32; } else { - HostAdapter->StrictRoundRobinModeSupported = false; + HostAdapter->StrictRoundRobinModeSupport = false; HostAdapter->MailboxCount = 32; HostAdapter->InitialCCBs = 32; HostAdapter->IncrementalCCBs = 4; @@ -1285,10 +1293,10 @@ sizeof(HostAdapter->ErrorRecoveryStrategy)); /* Tagged Queuing support is available and operates properly on all "W" Series - boards, on "C" Series boards with firmware version 4.22 and above, and on - "S" Series boards with firmware version 3.35 and above. Tagged Queuing is - disabled by default when the Tagged Queue Depth is 1 since queuing multiple - commands is not possible. + controllers, on "C" Series controllers with firmware version 4.22 and + above, and on "S" Series controllers with firmware version 3.35 and above. + Tagged Queuing is disabled by default when the Tagged Queue Depth is 1 + since queuing multiple commands is not possible. */ TaggedQueuingPermittedDefault = 0; if (HostAdapter->TaggedQueueDepth != 1) @@ -1471,7 +1479,8 @@ */ if (HostAdapter->DMA_Channel > 0) { - if (request_dma(HostAdapter->DMA_Channel, HostAdapter->BoardName) < 0) + if (request_dma(HostAdapter->DMA_Channel, + HostAdapter->ControllerName) < 0) { printk("scsi%d: UNABLE TO ACQUIRE DMA CHANNEL %d - DETACHING\n", HostAdapter->HostNumber, HostAdapter->DMA_Channel); @@ -1568,7 +1577,7 @@ { BusLogic_ExtendedMailboxRequest_T ExtendedMailboxRequest; BusLogic_RoundRobinModeRequest_T RoundRobinModeRequest; - BusLogic_WideModeCCBRequest_T WideModeCCBRequest; + BusLogic_SetCCBFormatRequest_T SetCCBFormatRequest; BusLogic_ModifyIOAddressRequest_T ModifyIOAddressRequest; int TargetID; /* @@ -1615,7 +1624,7 @@ Outgoing Mailboxes to find any that have new commands in them. Strict Round Robin Mode is significantly more efficient. */ - if (HostAdapter->StrictRoundRobinModeSupported) + if (HostAdapter->StrictRoundRobinModeSupport) { RoundRobinModeRequest = BusLogic_StrictRoundRobinMode; if (BusLogic_Command(HostAdapter, BusLogic_EnableStrictRoundRobinMode, @@ -1624,16 +1633,16 @@ return BusLogic_Failure(HostAdapter, "ENABLE STRICT ROUND ROBIN MODE"); } /* - For Wide SCSI Host Adapters, issue the Enable Wide Mode CCB command to - allow more than 8 Logical Units per Target Device to be supported. + For Host Adapters that support 64 LUN Format CCBs, issue the Set CCB Format + command to allow 64 Logical Units per Target Device. */ - if (HostAdapter->HostWideSCSI) + if (HostAdapter->Host64LUNSupport) { - WideModeCCBRequest = BusLogic_WideModeCCB; - if (BusLogic_Command(HostAdapter, BusLogic_EnableWideModeCCB, - &WideModeCCBRequest, - sizeof(WideModeCCBRequest), NULL, 0) < 0) - return BusLogic_Failure(HostAdapter, "ENABLE WIDE MODE CCB"); + SetCCBFormatRequest = BusLogic_64LUNFormatCCB; + if (BusLogic_Command(HostAdapter, BusLogic_SetCCBFormat, + &SetCCBFormatRequest, sizeof(SetCCBFormatRequest), + NULL, 0) < 0) + return BusLogic_Failure(HostAdapter, "SET CCB FORMAT"); } /* For PCI Host Adapters being accessed through the PCI compliant I/O @@ -1659,7 +1668,7 @@ Announce Successful Initialization. */ printk("scsi%d: *** %s Initialized Successfully ***\n", - HostAdapter->HostNumber, HostAdapter->BoardName); + HostAdapter->HostNumber, HostAdapter->ControllerName); /* Indicate the Host Adapter Initialization completed successfully. */ @@ -1668,12 +1677,12 @@ /* - BusLogic_InquireTargetDevices inquires about the Target Devices accessible + BusLogic_TargetDeviceInquiry inquires about the Target Devices accessible through Host Adapter and reports on the results. */ -static boolean BusLogic_InquireTargetDevices(BusLogic_HostAdapter_T - *HostAdapter) +static boolean BusLogic_TargetDeviceInquiry(BusLogic_HostAdapter_T + *HostAdapter) { BusLogic_InstalledDevices_T InstalledDevices; BusLogic_InstalledDevices8_T InstalledDevicesID0to7; @@ -1697,20 +1706,20 @@ return true; } /* - Issue the Inquire Devices command for boards with firmware version 4.25 or - later, or the Inquire Installed Devices ID 0 to 7 command for older boards. - This is necessary to force Synchronous Transfer Negotiation so that the - Inquire Setup Information and Inquire Synchronous Period commands will - return valid data. The Inquire Devices command is preferable to Inquire - Installed Devices ID 0 to 7 since it only probes Logical Unit 0 of each - Target Device. + Issue the Inquire Target Devices command for controllers with firmware + version 4.25 or later, or the Inquire Installed Devices ID 0 to 7 command + for older controllers. This is necessary to force Synchronous Transfer + Negotiation so that the Inquire Setup Information and Inquire Synchronous + Period commands will return valid data. The Inquire Target Devices command + is preferable to Inquire Installed Devices ID 0 to 7 since it only probes + Logical Unit 0 of each Target Device. */ if (strcmp(HostAdapter->FirmwareVersion, "4.25") >= 0) { - if (BusLogic_Command(HostAdapter, BusLogic_InquireDevices, NULL, 0, + if (BusLogic_Command(HostAdapter, BusLogic_InquireTargetDevices, NULL, 0, &InstalledDevices, sizeof(InstalledDevices)) != sizeof(InstalledDevices)) - return BusLogic_Failure(HostAdapter, "INQUIRE DEVICES"); + return BusLogic_Failure(HostAdapter, "INQUIRE TARGET DEVICES"); } else { @@ -1979,8 +1988,7 @@ Read the Host Adapter Configuration, Acquire the System Resources necessary to use Host Adapter and initialize the fields in the SCSI Host structure, then Test Interrupts, Create the Mailboxes and CCBs, - Initialize the Host Adapter, and finally Inquire about the Target - Devices. + Initialize the Host Adapter, and finally perform Target Device Inquiry. */ if (BusLogic_ReadHostAdapterConfiguration(HostAdapter) && BusLogic_AcquireResources(HostAdapter) && @@ -1988,7 +1996,7 @@ BusLogic_CreateMailboxes(HostAdapter) && BusLogic_CreateCCBs(HostAdapter) && BusLogic_InitializeHostAdapter(HostAdapter) && - BusLogic_InquireTargetDevices(HostAdapter)) + BusLogic_TargetDeviceInquiry(HostAdapter)) { /* Initialization has been completed successfully. Release and @@ -1998,7 +2006,7 @@ */ release_region(HostAdapter->IO_Address, BusLogic_IO_PortCount); request_region(HostAdapter->IO_Address, BusLogic_IO_PortCount, - HostAdapter->BoardName); + HostAdapter->ControllerName); BusLogic_InitializeHostStructure(HostAdapter, Host); BusLogicHostAdapterCount++; } @@ -2100,7 +2108,7 @@ HostStatus = DID_RESET; break; default: - printk("BusLogic: unknown Host Adapter Status 0x%02X\n", + printk("BusLogic: Unknown Host Adapter Status 0x%02X\n", HostAdapterStatus); HostStatus = DID_ERROR; break; @@ -2504,14 +2512,14 @@ CCB->TargetID = TargetID; CCB->LogicalUnit = LogicalUnit; /* - For Wide SCSI Host Adapters, Wide Mode CCBs are used to support more than - 8 Logical Units per Target, and this requires setting the overloaded + For Host Adapters that support it, 64 LUN Format CCBs are used to allow + 64 Logical Units per Target, and this requires setting the overloaded TagEnable field to Logical Unit bit 5. */ - if (HostAdapter->HostWideSCSI) + if (HostAdapter->Host64LUNSupport) { CCB->TagEnable = LogicalUnit >> 5; - CCB->WideModeTagEnable = false; + CCB->TagEnable64LUN = false; } else CCB->TagEnable = false; /* @@ -2519,14 +2527,19 @@ are sent to a Target Device be sent in a non Tagged Queue fashion so that the Host Adapter and Target Device can establish Synchronous and Wide Transfer before Queue Tag messages can interfere with the Synchronous and - Wide Negotiation message. By waiting to enable Tagged Queuing until after - the first BusLogic_PreferredQueueDepth commands have been sent, it is - assured that after a Reset any pending commands are resent before Tagged + Wide Negotiation messages. By waiting to enable Tagged Queuing until after + the first BusLogic_MaxTaggedQueueDepth commands have been queued, it is + assured that after a Reset any pending commands are requeued before Tagged Queuing is enabled and that the Tagged Queuing message will not occur while - the partition table is being printed. - */ - if (HostAdapter->TotalCommandCount[TargetID]++ == - BusLogic_PreferredTaggedQueueDepth && + the partition table is being printed. In addition, some devices do not + properly handle the transition from non-tagged to tagged commands, so it is + necessary to wait until there are no pending commands for a target device + before queuing tagged commands. + */ + if (HostAdapter->TotalCommandCount[TargetID]++ >= + BusLogic_MaxTaggedQueueDepth && + !HostAdapter->TaggedQueuingActive[TargetID] && + HostAdapter->ActiveCommandCount[TargetID] == 0 && (HostAdapter->TaggedQueuingPermitted & (1 << TargetID)) && Command->device->tagged_supported) { @@ -2544,11 +2557,11 @@ write nearer the head position continue to arrive without interruption. Therefore, for each Target Device this driver keeps track of the last time either the queue was empty or an Ordered Queue Tag was issued. If - more than 5 seconds (half the 10 second disk timeout) have elapsed - since this last sequence point, this command will be issued with an - Ordered Queue Tag rather than a Simple Queue Tag, which forces the - Target Device to complete all previously queued commands before this - command may be executed. + more than 5 seconds (one third of the 15 second disk timeout) have + elapsed since this last sequence point, this command will be issued + with an Ordered Queue Tag rather than a Simple Queue Tag, which forces + the Target Device to complete all previously queued commands before + this command may be executed. */ if (HostAdapter->ActiveCommandCount[TargetID] == 0) HostAdapter->LastSequencePoint[TargetID] = jiffies; @@ -2557,10 +2570,10 @@ HostAdapter->LastSequencePoint[TargetID] = jiffies; QueueTag = BusLogic_OrderedQueueTag; } - if (HostAdapter->HostWideSCSI) + if (HostAdapter->Host64LUNSupport) { - CCB->WideModeTagEnable = true; - CCB->WideModeQueueTag = QueueTag; + CCB->TagEnable64LUN = true; + CCB->QueueTag64LUN = QueueTag; } else { @@ -2757,9 +2770,10 @@ } if (Command == NULL) printk("scsi%d: Resetting %s due to SCSI Reset State Interrupt\n", - HostAdapter->HostNumber, HostAdapter->BoardName); + HostAdapter->HostNumber, HostAdapter->ControllerName); else printk("scsi%d: Resetting %s due to Target %d\n", - HostAdapter->HostNumber, HostAdapter->BoardName, Command->target); + HostAdapter->HostNumber, HostAdapter->ControllerName, + Command->target); /* Attempt to Reset and Reinitialize the Host Adapter. */ @@ -2767,7 +2781,7 @@ BusLogic_InitializeHostAdapter(HostAdapter))) { printk("scsi%d: Resetting %s Failed\n", - HostAdapter->HostNumber, HostAdapter->BoardName); + HostAdapter->HostNumber, HostAdapter->ControllerName); Result = SCSI_RESET_ERROR; goto Done; } @@ -3039,18 +3053,18 @@ /* BusLogic_BIOSDiskParameters returns the Heads/Sectors/Cylinders BIOS Disk - Parameters for Disk. The default disk geometry is 64 heads, 32 sectors, - and the appropriate number of cylinders so as not to exceed drive capacity. - In order for disks equal to or larger than 1 GB to be addressable by the - BIOS without exceeding the BIOS limitation of 1024 cylinders, Extended - Translation may be enabled in AutoSCSI on "W" and "C" Series boards or by a - dip switch setting on older boards. With Extended Translation enabled, - drives between 1 GB inclusive and 2 GB exclusive are given a disk geometry - of 128 heads and 32 sectors, and drives above 2 GB inclusive are given a - disk geometry of 255 heads and 63 sectors. However, if the BIOS detects - that the Extended Translation setting does not match the geometry in the - partition table, then the translation inferred from the partition table - will be used by the BIOS, and a warning may be displayed. + Parameters for Disk. The default disk geometry is 64 heads, 32 sectors, and + the appropriate number of cylinders so as not to exceed drive capacity. In + order for disks equal to or larger than 1 GB to be addressable by the BIOS + without exceeding the BIOS limitation of 1024 cylinders, Extended Translation + may be enabled in AutoSCSI on "W" and "C" Series controllers or by a dip + switch setting on older controllers. With Extended Translation enabled, + drives between 1 GB inclusive and 2 GB exclusive are given a disk geometry of + 128 heads and 32 sectors, and drives above 2 GB inclusive are given a disk + geometry of 255 heads and 63 sectors. However, if the BIOS detects that the + Extended Translation setting does not match the geometry in the partition + table, then the translation inferred from the partition table will be used by + the BIOS, and a warning may be displayed. */ int BusLogic_BIOSDiskParameters(SCSI_Disk_T *Disk, KernelDevice_T Device, diff -ur --new-file old/linux/drivers/scsi/BusLogic.h new/linux/drivers/scsi/BusLogic.h --- old/linux/drivers/scsi/BusLogic.h Thu Jun 6 01:54:14 1996 +++ new/linux/drivers/scsi/BusLogic.h Wed Jul 17 20:22:13 1996 @@ -141,19 +141,19 @@ /* - Define the possible Local Options. + Define the possible Probe Options. */ -#define BusLogic_InhibitTargetInquiry 1 +#define BusLogic_NoProbe 1 +#define BusLogic_NoProbeISA 2 +#define BusLogic_NoSortPCI 4 /* - Define the possible Probe Options. + Define the possible Local Options. */ -#define BusLogic_NoProbe 1 -#define BusLogic_NoProbeISA 2 -#define BusLogic_NoSortPCI 4 +#define BusLogic_InhibitTargetInquiry 1 /* @@ -209,7 +209,7 @@ #define BusLogic_CommandParameterRegister 1 /* WO register */ #define BusLogic_DataInRegister 1 /* RO register */ #define BusLogic_InterruptRegister 2 /* RO register */ -#define BusLogic_GeometryRegister 3 /* RO, undocumented */ +#define BusLogic_GeometryRegister 3 /* RO register */ /* @@ -250,7 +250,7 @@ /* - Define the bits in the undocumented read-only Geometry Register. + Define the bits in the read-only Geometry Register. */ #define BusLogic_Drive0Geometry 0x03 @@ -265,40 +265,50 @@ typedef enum { - BusLogic_TestCommandCompleteInterrupt = 0x00, /* documented */ - BusLogic_InitializeMailbox = 0x01, /* documented */ - BusLogic_ExecuteMailboxCommand = 0x02, /* documented */ - BusLogic_ExecuteBIOSCommand = 0x03, /* documented */ - BusLogic_InquireBoardID = 0x04, /* documented */ - BusLogic_EnableOutgoingMailboxAvailableInt = 0x05, /* documented */ - BusLogic_SetSCSISelectionTimeout = 0x06, /* documented */ - BusLogic_SetPreemptTimeOnBus = 0x07, /* documented */ - BusLogic_SetTimeOffBus = 0x08, /* ISA Bus only */ - BusLogic_SetBusTransferRate = 0x09, /* ISA Bus only */ - BusLogic_InquireInstalledDevicesID0to7 = 0x0A, /* documented */ - BusLogic_InquireConfiguration = 0x0B, /* documented */ - BusLogic_SetTargetMode = 0x0C, /* now undocumented */ - BusLogic_InquireSetupInformation = 0x0D, /* documented */ - BusLogic_WriteAdapterLocalRAM = 0x1A, /* documented */ - BusLogic_ReadAdapterLocalRAM = 0x1B, /* documented */ - BusLogic_WriteBusMasterChipFIFO = 0x1C, /* documented */ - BusLogic_ReadBusMasterChipFIFO = 0x1D, /* documented */ - BusLogic_EchoCommandData = 0x1F, /* documented */ - BusLogic_HostAdapterDiagnostic = 0x20, /* documented */ - BusLogic_SetAdapterOptions = 0x21, /* documented */ - BusLogic_InquireInstalledDevicesID8to15 = 0x23, /* Wide only */ - BusLogic_InquireDevices = 0x24, /* "W" and "C" only */ - BusLogic_InitializeExtendedMailbox = 0x81, /* documented */ - BusLogic_InquireFirmwareVersion3rdDigit = 0x84, /* undocumented */ - BusLogic_InquireFirmwareVersionLetter = 0x85, /* undocumented */ - BusLogic_InquireGenericIOPortInformation = 0x86, /* PCI only */ - BusLogic_InquireBoardModelNumber = 0x8B, /* undocumented */ - BusLogic_InquireSynchronousPeriod = 0x8C, /* undocumented */ - BusLogic_InquireExtendedSetupInformation = 0x8D, /* documented */ - BusLogic_EnableStrictRoundRobinMode = 0x8F, /* documented */ - BusLogic_FetchHostAdapterLocalRAM = 0x91, /* undocumented */ - BusLogic_ModifyIOAddress = 0x95, /* PCI only */ - BusLogic_EnableWideModeCCB = 0x96 /* Wide only */ + BusLogic_TestCommandCompleteInterrupt = 0x00, + BusLogic_InitializeMailbox = 0x01, + BusLogic_ExecuteMailboxCommand = 0x02, + BusLogic_ExecuteBIOSCommand = 0x03, + BusLogic_InquireBoardID = 0x04, + BusLogic_EnableOutgoingMailboxAvailableInt = 0x05, + BusLogic_SetSCSISelectionTimeout = 0x06, + BusLogic_SetPreemptTimeOnBus = 0x07, + BusLogic_SetTimeOffBus = 0x08, + BusLogic_SetBusTransferRate = 0x09, + BusLogic_InquireInstalledDevicesID0to7 = 0x0A, + BusLogic_InquireConfiguration = 0x0B, + BusLogic_EnableTargetMode = 0x0C, + BusLogic_InquireSetupInformation = 0x0D, + BusLogic_WriteAdapterLocalRAM = 0x1A, + BusLogic_ReadAdapterLocalRAM = 0x1B, + BusLogic_WriteBusMasterChipFIFO = 0x1C, + BusLogic_ReadBusMasterChipFIFO = 0x1D, + BusLogic_EchoCommandData = 0x1F, + BusLogic_HostAdapterDiagnostic = 0x20, + BusLogic_SetAdapterOptions = 0x21, + BusLogic_InquireInstalledDevicesID8to15 = 0x23, + BusLogic_InquireTargetDevices = 0x24, + BusLogic_DisableHostAdapterInterrupt = 0x25, + BusLogic_InitializeExtendedMailbox = 0x81, + BusLogic_ExecuteSCSICommand = 0x83, + BusLogic_InquireFirmwareVersion3rdDigit = 0x84, + BusLogic_InquireFirmwareVersionLetter = 0x85, + BusLogic_InquireGenericIOPortInformation = 0x86, + BusLogic_InquireControllerModelNumber = 0x8B, + BusLogic_InquireSynchronousPeriod = 0x8C, + BusLogic_InquireExtendedSetupInformation = 0x8D, + BusLogic_EnableStrictRoundRobinMode = 0x8F, + BusLogic_StoreHostAdapterLocalRAM = 0x90, + BusLogic_FetchHostAdapterLocalRAM = 0x91, + BusLogic_StoreLocalDataInEEPROM = 0x92, + BusLogic_UploadAutoSCSICode = 0x94, + BusLogic_ModifyIOAddress = 0x95, + BusLogic_SetCCBFormat = 0x96, + BusLogic_WriteInquiryBuffer = 0x9A, + BusLogic_ReadInquiryBuffer = 0x9B, + BusLogic_FlashROMUploadDownload = 0xA7, + BusLogic_ReadSCAMData = 0xA8, + BusLogic_WriteSCAMData = 0xA9 } BusLogic_OperationCode_T; @@ -328,10 +338,10 @@ /* - Define the Inquire Devices reply type. Inquire Devices only tests Logical - Unit 0 of each Target Device unlike Inquire Installed Devices which tests - Logical Units 0 - 7. Two bytes are returned, where bit 0 set indicates - that Target Device 0 exists, and so on. + Define the Inquire Target Devices reply type. Inquire Target Devices only + tests Logical Unit 0 of each Target Device unlike the Inquire Installed + Devices commands which test Logical Units 0 - 7. Two bytes are returned, + where bit 0 set indicates that Target Device 0 exists, and so on. */ typedef unsigned short BusLogic_InstalledDevices_T; @@ -393,7 +403,7 @@ unsigned char DisconnectPermittedID0to7; /* Byte 16 */ unsigned char Signature; /* Byte 17 */ unsigned char CharacterD; /* Byte 18 */ - unsigned char BusLetter; /* Byte 19 */ + unsigned char HostBusType; /* Byte 19 */ unsigned char :8; /* Byte 20 */ unsigned char :8; /* Byte 21 */ BusLogic_SynchronousValues8_T SynchronousValuesID8to15; /* Bytes 22-29 */ @@ -449,10 +459,10 @@ /* - Define the Inquire Board Model Number reply type. + Define the Inquire Controller Model Number reply type. */ -typedef unsigned char BusLogic_BoardModelNumber_T[5]; +typedef unsigned char BusLogic_ControllerModelNumber_T[5]; /* @@ -483,7 +493,8 @@ boolean HostDifferentialSCSI:1; /* Byte 13 Bit 1 */ boolean HostAutomaticConfiguration:1; /* Byte 13 Bit 2 */ boolean HostUltraSCSI:1; /* Byte 13 Bit 3 */ - unsigned char :4; /* Byte 13 Bits 4-7 */ + boolean HostSmartTermination:1; /* Byte 13 Bit 4 */ + unsigned char :3; /* Byte 13 Bits 5-7 */ } BusLogic_ExtendedSetupInformation_T; @@ -559,20 +570,21 @@ /* - Define the Enable Wide Mode SCSI CCB request type. Wide Mode CCBs are - necessary to support more than 8 Logical Units per Target Device. + Define the Set CCB Format request type. 64 LUN Format CCBs are necessary to + support 64 Logical Units per Target Device. 8 LUN Format CCBs only support 8 + Logical Units per Target Device. */ -#define BusLogic_NormalModeCCB 0x00 -#define BusLogic_WideModeCCB 0x01 +#define BusLogic_8LUNFormatCCB 0x00 +#define BusLogic_64LUNFormatCCB 0x01 -typedef unsigned char BusLogic_WideModeCCBRequest_T; +typedef unsigned char BusLogic_SetCCBFormatRequest_T; /* Define the Requested Reply Length type used by the Inquire Setup Information, - Inquire Board Model Number, Inquire Synchronous Period, and Inquire Extended - Setup Information commands. + Inquire Controller Model Number, Inquire Synchronous Period, and Inquire + Extended Setup Information commands. */ typedef unsigned char BusLogic_RequestedReplyLength_T; @@ -732,13 +744,13 @@ /* Define the 32 Bit Mode Command Control Block (CCB) structure. The first 40 bytes are defined by the Host Adapter Firmware Interface. The remaining - components are defined by the Linux BusLogic Driver. Wide Mode CCBs differ - from standard 32 Bit Mode CCBs only in having the TagEnable and QueueTag - fields moved from byte 17 to byte 1, and the Logical Unit field in byte 17 - expanded to 6 bits; unfortunately, using a union of structs containing - enumeration type bitfields to provide both definitions leads to packing - problems, so the following definition is used which requires setting - TagEnable to Logical Unit bit 5 in Wide Mode CCBs. + components are defined by the Linux BusLogic Driver. 64 LUN Format CCBs + differ from standard 8 LUN Format 32 Bit Mode CCBs only in having the + TagEnable and QueueTag fields moved from byte 17 to byte 1, and the Logical + Unit field in byte 17 expanded to 6 bits; unfortunately, using a union of + structs containing enumeration type bitfields to provide both definitions + leads to packing problems, so the following definition is used which requires + setting TagEnable to Logical Unit bit 5 in 64 LUN Format CCBs. */ typedef struct BusLogic_CCB @@ -749,8 +761,8 @@ BusLogic_CCB_Opcode_T Opcode:8; /* Byte 0 */ unsigned char :3; /* Byte 1 Bits 0-2 */ BusLogic_DataDirection_T DataDirection:2; /* Byte 1 Bits 3-4 */ - boolean WideModeTagEnable:1; /* Byte 1 Bit 5 */ - BusLogic_QueueTag_T WideModeQueueTag:2; /* Byte 1 Bits 6-7 */ + boolean TagEnable64LUN:1; /* Byte 1 Bit 5 */ + BusLogic_QueueTag_T QueueTag64LUN:2; /* Byte 1 Bits 6-7 */ unsigned char CDB_Length; /* Byte 2 */ unsigned char SenseDataLength; /* Byte 3 */ unsigned int DataLength; /* Bytes 4-7 */ @@ -863,7 +875,7 @@ unsigned char HostNumber; unsigned char ModelName[9]; unsigned char FirmwareVersion[6]; - unsigned char BoardName[18]; + unsigned char ControllerName[18]; unsigned char InterruptLabel[62]; unsigned char IRQ_Channel; unsigned char DMA_Channel; @@ -883,7 +895,8 @@ boolean LowByteTerminated:1; boolean HighByteTerminated:1; boolean BounceBuffersRequired:1; - boolean StrictRoundRobinModeSupported:1; + boolean StrictRoundRobinModeSupport:1; + boolean Host64LUNSupport:1; boolean HostAdapterResetRequested:1; volatile boolean HostAdapterCommandCompleted:1; unsigned short HostAdapterScatterGatherLimit; @@ -1057,7 +1070,7 @@ unsigned long ProcessorFlags; save_flags(ProcessorFlags); sti(); - while (jiffies < TimeoutJiffies) ; + while (jiffies < TimeoutJiffies) barrier(); restore_flags(ProcessorFlags); } diff -ur --new-file old/linux/drivers/scsi/ChangeLog.ncr53c8xx new/linux/drivers/scsi/ChangeLog.ncr53c8xx --- old/linux/drivers/scsi/ChangeLog.ncr53c8xx Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/scsi/ChangeLog.ncr53c8xx Tue Jul 23 09:26:41 1996 @@ -0,0 +1,654 @@ +Sun Jul 21 00:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c, README.ncr53c8xx + Add the ncr53c8xx_select_queue_depths() function. + Set queue_depth to SCSI_NCR_MAX_TAGS (4 by default) for devices that + support tagged command queueing. + For other devices, set queue_depth to 1. No need to queue a command + to the driver if this command cannot be sent to the device. + Each time the driver hide io requests from the kernel and/or from the + driver, it may break a little (or a lot) optimization algorithms that + try to increase throughput by reordering io requests. + It is better to enable the disk write caching to reduce latencies for + write operations, and to trust asynchronous read ahead from the device + and from the kernel that can reduce latencies for read operations, + even when tagged command queuing is not supported or enabled. + +Sat Jul 20 20:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c + Minor changes: + - Problem of "CCB address mismatch" that happens with the 3 versions + of the driver. The CCB is correct and Stefan Esser suggests a little + patch that seems to be a bypass. + Stefan says he will change that in a future version of the BSD driver. + - Set burst transfers to 8 for 815 chips. + +Sun Jul 14 15:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c, Configure.help + Memory mapped io donnot work under linux/Alpha for the driver. + For the moment it is better to not support this feature for this + architecture. + +Tue Jul 09 20:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c + Garbage printed out with the following command (fixed): + - cat /proc/scsi/ncr53c8xx/0 + +Sun Jul 07 20:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c + Tagged command queueing cannot be disabled at run time. + I probably never try that because I felt the risk. + Shortest patch sent to Linus. I have to plan something better. + +Wed Jul 03 23:00 1996 Gerard Roudier (groudier@club-internet.fr) + Release 1.12a + Tested linux releases: 1.2.13, 2.0.0, 2.0.1 + +Mon Jul 01 21:00 1996 Gerard Roudier (groudier@club-internet.fr) + ncr53c8xx.h, ncr53c8xx.c + Add "clearprof" user command that clear the profile counters. + Automatically clear profile counters when num_kbytes=1000000000 + in order to avoid ugly overflow. + Donnot compile user command code and profile data with 1.2.13. + +Wed Jun 29 20:38 1996 Gerard Roudier (groudier@club-internet.fr) + Matthew Geier reported to me a weird problem of unexpected + disconnection while asynchronous negotiation. + The message sent by the driver is 1-3-1-ff-00. I sent a patch to + Matthew that change the message to 1-3-1-00-00. + The sync msgout was correct however some devices might be to happy + with ff. + +Wed Jun 26 22:57 1996 Gerard Roudier (groudier@club-internet.fr) + Patch no 4 sent to Harald. + The drived used "wtime" for timeouts adn time measurements. + I change for jiffies. + Work with my P133. + +Mon Jun 24 23:05 1996 Gerard Roudier (groudier@club-internet.fr) + Patch no 3 sent to Harald. + +Sun Jun 23 22:29 1996 Gerard Roudier (groudier@club-internet.fr) + Patch no 2 sent to Harald. + I think that the driver have some chance to work. + +Sun Jun 23 15:00 1996 Gerard Roudier (groudier@club-internet.fr) + Harald Koenig is interested in the adaptation of the driver to + Linux/Alpha. + I have prepared a patch and sent it to Harald. + +Sun Jun 16 19:00 1996 Gerard Roudier (groudier@club-internet.fr) + Release 1.11 + Tested linux releases: 1.2.13, 2.0.0 + +Sat Jun 15 23:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.h, Configure.help, scsi/Config.in + Add CONFIG_SCSI_NCR53C8XX_IOMAPPED config option. + Prepare the 2.0.0 with the new version of the driver. + +Wed Jun 12 23:00 1996 Gerard Roudier (groudier@club-internet.fr) + Rewrite the README file. + Add some documentations of the proc file system support. + +Sun Jun 9 18:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c + Add proc filesystem support of the driver. + Read operations returns profile information. + Write operations send control commands to the host adapter driver. + +Wed Jun 5 22:00 1996 Gerard Roudier (groudier@club-internet.fr) + Change xfer direction for SCAN command to write. + Was bogus. + +Tue May 30 18:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c + Set the DMA FIFO to 88 for 825A and 875 boards. + The previous value of 536 is bogus since the script only read 7 + bits for the fifo size (thanks to Stefan). + +Mon May 27 18:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c + Correct the xfer direction guessing for scanner SCAN command (write). + +Mon May 27 18:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c + Add the following config options: + SCSI_NCR_DISABLE_MPARITY_CHECK : disable master parity checking. + SCSI_NCR_DISABLE_PARITY_CHECK : disable scsi parity checking. + SCSI_NCR_FORCE_SYNC_NEGO : force sync nego for all scsi 2 devices. + +Sat May 25 22:00 1996 Gerard Roudier (groudier@club-internet.fr) + Release 1.10 + Tested linux releases: 1.2.13, 1.3.45, 1.3.71, 1.3.90, 1.3.100 + 1.99.6, 1.99.7 + Switch between Drew's driver and Bsd driver tested for 1.99.7. + Both driver was made as modules. + +Sat May 25 16:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c + Some weird problems happen with multi-lun configurations and HDs. + SDTR seems to be sent with TEST UNIT READY of lun 1. + Tagged Queue cannot be enabled. It seems that inqdata are + filled with garbage probably due to some INQUIRY command to + lun 1. + I have fixed the problem as follow: + - negotiation are initiated only with a command to lun 0. + - inquiry data are store only for lun 0. + +Wed May 22 22:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c, ncr53c8xx.h + Have prepared the patch that allow to install the driver in the + kernel tree, without moving Drew's one. + Seems to work. However, I have to check that nothing has been + broken for 1.2.13 and 1.3.45 to 1.3.100. + +Sun May 4 22:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.h + Adapt the source to some modifications of the linux tree of 1.3.98. + (include/linux/scsicam.h moved to include/scsi/scsicam.h) + +Thu Apr 25 21:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.h, ncr53c8xx.c + Release 1.9 + Prepare conditionnal compilations for the future Linux version(s). + Assume that these versions will be nicely compatible with current + one. + 1.3.255, 1.4.0 or 2.0.0 ? + I suggest 3.0.0 for some obvious reason. + +Wed Apr 24 23:15 1996 Gerard Roudier (groudier@club-internet.fr) + * Install.ncr53c8xx + Add Patch-Current.ncr53c8xx to the distribution. + This patch is applied to the scsi Makefile at installation time for + Linux release V.P.S (V*1000000000+P*100000000+S > 1300000094). + Each time it'll be necessary I will send the patch corresponding to + the current Linux release to the linux-scsi@vger.rutgers.edu. + +Sun Apr 21 19:00 1996 Gerard Roudier (groudier@club-internet.fr) + * README.ncr53c8xx + Update Bonnie results of linux-1.3.92 + prepatch read-ahead 1.3.93. + Results are so good that I must remove FreeBSD-2.0.5 results from the + README file, otherwise I should cause trouble for myself. + +Sun Apr 07 21:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.h + Define SCSI_NCR_MAX_LUN (8) inconditionaly. + Previous releases did not work for multi-lun devices. + This definition was wrongly conditionned: + (SCSI_CONFIG_MULTI_LUN instead of CONFIG_SCSI_MULTI_LUN). + No luck, since I donnot have multi-lun devices and could'nt + test it. + Some tests under linux-1.3.84 with an experimental patch that + try to do asynchronous read-ahead. + +Wed Apr 03 23:15 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.h, ncr53c8xx.c + Change some wrong "assert (target == cmd->target & 7)" to + "assert (target == (cmd->target & 0xf)". + Remove NCR_TIMEOUT_ALERT from ncr53c8xx.c + Add SCSI_NCR_TIMEOUT_ALERT to ncr53c8xx.h + +Sun Mar 24 21:15 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.h + During "make dep" of linux-1.2.13, LINUX_VERSION_CODE is undefined. + Have to assume 1.2.13 in such situation. + Release 1.8 + +Sun Mar 24 21:00 1996 Gerard Roudier (groudier@club-internet.fr) + * README.ncr53c8xx + Make changes according to the new uninstallation procedure. + +Sun Mar 24 20:00 1996 Gerard Roudier (groudier@club-internet.fr) + * Uninstall.ncr53c8xx + Add an uninstallation script to the distribution. + This shell script restore the standard driver. + Very usefull for people who prefers to use a driver that + does not support: + - Master parity check + - Tagged command queuing + - Fast Wide Scsi-2 features (up to 20 MB/sec) + and that would be capable to reject a Wide Negotiation that it had + previously initiated. + +Sat Mar 23 22:00 1996 Gerard Roudier (groudier@club-internet.fr) + * README.ncr53c8xx + Make changes according to the new installation procedure. + +Fri Mar 22 23:00 1996 Gerard Roudier (groudier@club-internet.fr) + * Install.ncr53c8xx + Add an installation script to the distribution. + 3 differents patches are necessary: + - linux-1.2.13 + - linux-1.3.45 to linux-1.3.49 + - linux-1.3.50 to linux-1.3.77 + +Wed Mar 13 22:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c, ncr53c8xx.h + Add share irq support. + This facility appears with linux-1.3.70. It seems that the + corresponding code of the kernel was questionnable before 1.3.72. + I decide to support this options from linux-1.3.72 and above. + (Add define option SCSI_NCR_SHARE_IRQ) + Release 1.7 + +Tue Mar 12 22:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c + Download BSD ncr.c 1.67 and apply the correction of negotiations order. + Now the Wide and Sync negotiation are done in the proper order. + (Problem reported by Johannes Plass). + Round up correctly the announced speed in MB/sec. + +Tue Mar 05 22:00 1996 Gerard Roudier (groudier@club-internet.fr) + * README.ncr53c8xx + Have to upload release 1.6 for users of linux-1.3.70-71 + +Mon Mar 04 16:00 1996 Gerard Roudier (groudier@club-internet.fr) + * README.ncr53c8xx + Add some Bonnie results to the README file. + +Sun Mar 03 20:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c + Make changes for linux-1.3.70 according to the new specification of + irq services interface (request_irq(), free_irq()). + With 26 letters, "_", and 10 digits we can build about: + 53x62**9 C names of 10 characters. + Why to use SAME function names with DIFFERENT parameters ? + +Sat Mar 02 22:30 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c + Using SIMPLE QUEUE TAG for all operations is good for performances, + but may be bad for assumed timeout values. + Under heavy disk load (Bonnie), the drive may start IO process of a + command, then disconnect, then execute lots of other commands + before completing the interrupted command. + The standard value of SD_TIMEOUT (6 sec or 7 sec) seems (is) too short. + I fix the problem by forcing an ORDERED QUEUE TAG for the next + command when I found some "old" pending command. + "Old" means that they might be timeouted in a few seconds. + Add NCR_TIMEOUT_ALERT and set it to 3 seconds. + +Fri Mar 01 22:30 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.h, ncr53c8xx.c + Add define SCSI_NCR_SEGMENT_SIZE and set it by default to 512. + If undefined, the driver use the scatter list given by the upper + scsi driver, else it tries to split segments into shorter one + according to the value of SCSI_NCR_SEGMENT_SIZE. + +Tue Feb 27 21:30 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.h + Set sg_tablesize to 127 = SCSI_NCR_MAX_SCATTER-1. + (was 64 = SCSI_NCR_MAX_SCATTER/2). + May increase the speed (about 20%) for linear read/write operations. + Bonnie results may be better, but I prefered the previous + value. + +Tue Feb 27 21:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr54c8xx.c, ncr53c8xx.h + Tagged command queueing seems to affect linux-1.3.XY kernels. + I decide to disable tagged queue by default and to provide a command + tool to enable it per device after boot-up. + Add scsitag.c to the distribution. + Usage: scsitag device + Examples: scsitag /dev/sda + scsitag /dev/sdb + +Sun Feb 25 14:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c, ncr53c8xx.h + Add INQ7_Default definition and set the target capabilities to this + value by default. + Add some code to reject a synchronous negotiation request from a target + that is defined as not capable of Sync in the table of capabilities. + +Sat Feb 24 23:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c + Add some code to fill some write-only host instance fields: + - base + - io_port + - n_io_port + - dma_channel + This fields may be used with some "standard" drivers that do not + process correctly the release function. + +Fri Feb 23 23:00 1996 Gerard Roudier (groudier@club-internet.fr) + I receive a mail from Jason Duerstock. + A new bug in ncrBsd2Linux which is probably outside the driver code + and inside Linux kernel code. + The kernel memory is quite corrupted and we cannot get any information + by looking into the messages about the crash. However Linus see a bug in + ncrBsd2Linux because it is a "non standard" driver. + I think too that ncrBsd2Linux is not a standard driver of Linux kernel, + because it has no bugs enough to become standard for Linux. + Drew's driver is quite standard. + +Wed Feb 21 23:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c, ncr53c8xx.h + I incorporate the differences between FreeBSD ncr.c revision 1.62 and + revision 1.64. + - Some cosmetic changes. + - Use M_SIMPLE_TAG by default (even for write operations). + I seems to me that SIMPLE TAG is safe only if the flag "queue + algorithm modifier" is set to zero. + I will ask some questions to Stefan Esser about this. + Add option SCSI_NCR_ALWAYS_SIMPLE_TAG in ncr53c8xx.h. + +Fri Feb 16 23:00 1996 Gerard Roudier (groudier@club-internet.fr) + I have found the bug. It is a recursion in __get_free_pages(). + I will send a mail to Linus about this. + +Sat Feb 10 20:00 1996 Gerard Roudier (groudier@club-internet.fr) + I am sure that the kernel stack overflow is due to a severe bug in + the Linux kernel. + I decide to try to find the bug by myself. + +Fri Feb 09 20:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c, ncr53c8xx.h + Limit commands per lun to 2 for linux-1.3.XY. + The patch-1.3.60 does not correct the kernel stack overflow problem. + I decide to make some tests with Drew's driver and Bsd2Linux with same + working conditions (3 commands per lun, FAST SCSI, no command queueing). + I get the stack overflow problem with the 2 drivers at the same + frequency. + With only 2 commands per lun, I dont have the problem with any driver. + It seems that the madness of recursion and the recent introduction of + the silly generic read function have broken performance and reliability + of scsi drivers. + +Thu Feb 08 23:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c, ncr_attach() + Release memory mapped region and io port if initialisation + does not succeed. + +Thu Feb 08 22:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c, ncr53c8xx.c + Try to spare some CPU time in queue_command() function and interrupt + handler: + Add SCSI_NCR_PARANOIA define option in ncr53c8xx.h. + Add SCSI_NCR_PROFILE define option in ncr53c8xx.h. + Avoid useless code and function calls. + +Tue Feb 06 21:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c, ncr53c8xx.h, ncr_timeout() + Add SCSI_NCR_BROKEN_INTR define option in ncr53c8xx.h. + If this option is set, the timeout handler polls the interrupt status + register every tick (10 ms). So, boards with broken interrupt can work. + +Mon Feb 05 21:30 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c + Print the correct speed, for devices with successfull wide negotiation. + For same period, such devices are two times faster then narrow ones. + +Mon Feb 05 21:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.h, ncr53c8xx.c, ncr_attach() + Add define SCSI_NCR_SETTLE_TIME in header file and set it by default + to 2 seconds. + +Sat Jan 27 14:00 1996 Gerard Roudier (groudier@club-internet.fr) + Upload release 1.3 + +Wed Jan 24 24:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c + Update from ncr Bsd 1.60 (Stefan Esser): + The handshake timeout is disabled, since + a few devices will delay ACK for more than a + second: Scanner, CDROM writer and a few old hard + disk drives. + +Wed Jan 24 22:30 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c + Set the selection timeout to 0.4 sec, since 0.25 sec + is recommended for scsi-1 devices. + Note that the Bsd ncr driver sets this timeout to 0.1 sec + and the linux standard ncr driver sets it to 0.8 sec. + +Wed Jan 24 22:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c + Add a 5 seconds delay after chip initialization, + waiting for scsi devices to settle their stomach, + as FreeBSD generic scsi driver does. + +Tue Jan 23 23:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c + Set burst length value according to chip type. + The original Bsd ncr driver sets burst length to 16 for + all chip types. + +Tue Jan 16 23:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c, ncr53c8xx.h + Add comments to linux specific glue code. + +Mon Jan 15 22:00 1996 Gerard Roudier (groudier@club-internet.fr) + io mapped versus memory mapped. + * ncr53c8xx.c + Add some code to dynamicaly switch to io mapped if memory mapped + does not work. + No more need to reconfigure, compile and link the kernel if + memory mapped is not possible. + +Sun Jan 14 18:00 1996 Gerard Roudier (groudier@club-internet.fr) + Patch sent to ncr mailing list by Jason Duerstock + + I have omitted to provide the proc_dir_entry to the middle + scsi driver. + * ncr53c8xxx.c + Add the declaration of the ncr53c8xx proc_dir_entry and return + the pointer to middle scsi driver. + +Sat Jan 13 01:00 1996 Gerard Roudier (groudier@club-internet.fr) + ncrBsd2Linux 1.1 is ready. + Upload to sunsite immediatly. + +Fri Jan 12 23:45 1996 Gerard Roudier (groudier@club-internet.fr) + It seems that scsi-2 devices too may cause problems because they + have flawes in the firmware. + * ncr53c8xx.h + I add a table of capabilities per target. + This table contains one byte per target. The value of this byte + is anded with byte 7 of INQUIRY data. + Edit ncr53c8xx.h and read the corresponding comments for more + details. + +Wed Jan 10 22:35 1996 Gerard Roudier (groudier@club-internet.fr) + I have some time to read the scsi-1 specifications. + Some very old scsi devices may cause problems with the ncr Bsd driver + for the following raisons: + The Synchronous Negotiation protocol was optional. + The standardized INQUIRY data does not include the byte 7 of + the scsi-2 specifications which contains the capabilities of + the device. + I think that negotiation with such devices are very questionnable. + * ncr53c8xx.c + ncrBsd2Linux 1.1 does not negotiate with scsi-1 devices. + +Sat Jan 06 21:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c function ncr_attach() + Disable chip interrupt before soft reset in attach procedure. + When loadlin is used to boot the system, the state of the NCR chip + is unpredicable. This modification avoid unexpected interrupts. + +Thu Jan 04 23:45 1996 Gerard Roudier (groudier@club-internet.fr) + ncrBsd2Linux 1.0 is ready. + Upload to sunsite immediatly. + +Tue Jan 02 23:00 1996 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c + Add a waiting list for Scsi Commands than can be inserted + into the start queue immediatly. + When a command complete, the waiting commands are requeued by calling + the queuecommand() function. + +Sun Dec 31 23:59 1995 Gerard Roudier (groudier@club-internet.fr) + * ncr53c8xx.c + Use kmalloc()/kfree() for internal data structures allocation to + avoid scsi memory pool shortage. + +Sat Dec 30 23:00 1995 Gerard Roudier (groudier@club-internet.fr) + ncrBsd2Linux can now use memory mapped IO. + Works fine. + * ncr53c8xx.c + Call vremap() from ncr_attach() to map the physical page which + contains the memory IO window. + Call vfree() from ncr_detach() (release module). + +Fri Dec 29 23:45 1995 Gerard Roudier (groudier@club-internet.fr) + ncrBsd2Linux can now be configured as a module. + Works fine. + * ncr53c8xx.c: add new functions ncr53c8xx_release() and ncr_detach() + Add the code to (per host): + Stop the timer. + Stop the chip. + Free allocated memory. + +Fri Dec 29 23:00 1995 Gerard Roudier (groudier@club-internet.fr) + Problem: detection routine returns 0 and can detect only one host. + * ncr53c8xx.c function ncr_attach() + ncr_attach() now returns 0 on success and -1 on error. + ncr53c8xx_detect() returns the number of detected hosts. + +Thu Dec 28 22:00 1995 Gerard Roudier (groudier@club-internet.fr) + I must upload the new version which corrects the severe problem with + WRITE_10 command. + Release 0.5 + Known or probable problems with this ncr driver release: + -------------------------------------------------------- + Same as the previous release. + +Wed Dec 27 23:00 1995 Gerard Roudier (groudier@club-internet.fr) + Problem: + System CRASH or scsi ERROR "extra data disgarded" on WRITE(10) + command. + * ncr53c8xx.c function guess_xfer_direction() + I add the WRITE(10) (0x2A) into the list of Data Out scsi commands. + It was a big mistake. + This BUG was introduced in the release 0.3 and is obvious present in + the release 0.4. + +Wed Dec 27 22:00 1995 Gerard Roudier (groudier@club-internet.fr) + Problem: + When I was testing tagged command queueing and disconnections + with one hard disk at a time (IBM S12), the script process hung + every 5 minutes with a non empty stall queue. + * ncr53c8xx.c function ncr_exception() + I replace "OUTB (nc_istat, INTF)" by + "OUTB (nc_istat, (istat & SIGP) | INTF)". + This statement cleared the INTF condition, but cleared the SIGP flag too. + (This bug is in the original FreeBSD ncr driver). + +Mon Dec 25 22:00 1995 Gerard Roudier (groudier@club-internet.fr) + Release 0.4 + Known or probable problems with this ncr driver release: + -------------------------------------------------------- + Hardware (or software) conflicts with some ethernet cards. + See release 0.2 above. + Crash with Intel saturn chipset with write-back cache enabled. + The SCSI SCRIPT access the internal registers of + the NCR chip by memory addressing. + Ensure that the memory area of the NCR chip is not cacheable. + Use scanpci to get the base memory address of the ncr chip. + The 128 bytes following this address must not be cached. + +Sat Dec 23 22:00 1995 Gerard Roudier (groudier@club-internet.fr) + Problem: + FreeBSD driver important comments + --------------------------------- + We try to reduce the number of interrupts caused + by unexpected phase changes due to disconnects. + A typical harddisk may disconnect before ANY block. + If we wanted to avoid unexpected phase changes at all + we had to use a break point every 512 bytes. + Of course the number of scatter/gather blocks is + limited. + * ncr53c8xx.c function ncr_scatter() + This function has been rewritten according to the above comments. + The Linux scatter list is scanned, and blocks are broken as possible + into 512 bytes chunks. + +Wed Dec 22 22:00 1995 Gerard Roudier (groudier@club-internet.fr) + Problem: ensure that there are enough allocated Command Control Blocks + for each unit to enqueue commands according to cmd_per_lun. + * ncr53c8xx.c function ncr_allocate_ccb() + Allocate all required ccb(s) instead of one at a time. + +Mon Dec 18 23:00 1995 Gerard Roudier (groudier@club-internet.fr) + Problem: A copy of the system time is used to compute timeouts. + When the system time is changed , we can get spurious timeouts + if scsi commands are pending. + * ncr53c8xx.c function ncr_timeout() + In FreeBSD the kernel time (volatile struct timeval time) is not + affected by settimeofday() or other change time functions. + For Linux, I replace "time" by "xtime". But "xtime" is the system time, + and is affected by change time functions. + If we detect a change <=-1s or >1s we assume system time has been changed. + For all active ccb(s), we recompute tlimit. + We set heartbeat to thistime to prevent spurious chip reset. + +Sun Dec 17 23:00 1995 Gerard Roudier (groudier@club-internet.fr) + Release 0.3. + +Sun Dec 17 11:00 1995 Gerard Roudier (groudier@club-internet.fr) + + Problem: Linux middle-level scsi driver does not provide the + direction of transfert in scsi command parameters. + FreeBSD ncr driver need this information to patch the SCSI script + for SAVE DATA POINTER and to check actual data transfer direction. + * ncr53c8xx.c + I add the function guess_xfer_direction(int opcode) which try to + guess the transfer direction. + Unfortunately my documentation about SCSI-II standard is very old. + It does not contain PHOTO-CD command specifications. + I assume input transfer direction, for unknown command. (not perfect) + +Wed Dec 15 23:00 1995 Gerard Roudier (groudier@club-internet.fr) + + It's time to schedule the release 0.2 + Known or probable problems with this ncr driver release: + -------------------------------------------------------- + Scsi tapes do not work. + scsi-config-1.5 does not work too. + Hardware (or software) conflicts with some ethernet cards. + The linux native ncr53c810 scsi driver does'not use memory + mapped IO at all. + The BSD driver can use memory mapped IO. + Under Linux, i seems to be difficult (or impossible) to map + a PCI memory area. So I decide to use normal IO in the code of + the ported driver. + However, the SCSI SCRIPT access the internal registers of + the NCR chip by memory addressing. + EThernet cards use a memory area to communicate with the system. + I think that this memory area conflicts with the memory area + used by the NCR chip. + The configuration diskette of your ethernet card can help you + to fix the problem (try sofware configurations). + +Wed Dec 15 22:00 1995 Gerard Roudier (groudier@club-internet.fr) + + Problem: detection of CD change did not work. + * ncr53c8xx.c + Signal a CHECK_CONDITION (S_CHECK_COND) to the middle-level + scsi drivers when the scsi completion status = S_SENSE|S_GOOD. + + Problem: System hang with status <4/82> after mounting the root + partition. System disk is a QUANTUM EMPIRE 1080 S. + Submitted by rwilhelm@Physik.TU-Muenchen.DE (Robert Wilhelm) + Thu, 14 Dec 1995 10:18:43 +0100 (MET) + * ncr53c8xx.c + Signal a CHECK_CONDITION (S_CHECK_COND) to the middle-level + scsi drivers when the scsi completion status = S_SENSE|S_CHECK_COND. + (HS_COMPLETE=4, S_SENSE|S_CHECK_COND=x82). + I can't test this fix. I think that it should work. + +Thu Dec 14 22:00 1995 Gerard Roudier (groudier@club-internet.fr) + + Problem submitted by Bill Dyess Tue 12 Dec 1995 + Only one lun detected on a Pioneer DRM-602X 6-disk CD-ROM changer. + * ncr53c8xx.h, ncr53c8xx.c + Define NCR_SCSI_MAX_LUN to 8 if the Linux configuration flag + SCSI_CONFIG_MULTI_LUN is set. + My CD device has only one lun. I can't test multi-lun device, + but I think that it should work. + + * ncr53c8xx.c + Write the ncr_abort_command() and ncr_reset_command() functions. + I intend to test these functions next week. + +Sun Dec 10 22:00 1995 Gerard Roudier (groudier@club-internet.fr) + * Release 0.1 + Works fine with hard disks under Linux 1.2.13 and Linux 1.3.45. diff -ur --new-file old/linux/drivers/scsi/Config.in new/linux/drivers/scsi/Config.in --- old/linux/drivers/scsi/Config.in Fri Jun 7 10:53:09 1996 +++ new/linux/drivers/scsi/Config.in Sun Jul 7 10:18:51 1996 @@ -44,13 +44,25 @@ bool ' allow DISCONNECT' CONFIG_SCSI_NCR53C7xx_DISCONNECT fi fi +if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_NCR53C7xx" != "y" ]; then + dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI + if [ "$CONFIG_SCSI_NCR53C8XX" != "n" ]; then + bool ' enable tagged command queueing' CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE + bool ' force normal IO' CONFIG_SCSI_NCR53C8XX_IOMAPPED + bool ' not allow targets to disconnect' CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT + bool ' force asynchronous transfer mode' CONFIG_SCSI_NCR53C8XX_FORCE_ASYNCHRONOUS + bool ' force synchronous negotiation' CONFIG_SCSI_NCR53C8XX_FORCE_SYNC_NEGO + fi + if [ "$CONFIG_SCSI_NCR53C8XX" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' disable master parity checking' CONFIG_SCSI_NCR53C8XX_DISABLE_MPARITY_CHECK + bool ' disable scsi parity checking' CONFIG_SCSI_NCR53C8XX_DISABLE_PARITY_CHECK + fi +fi dep_tristate 'IOMEGA Parallel Port ZIP drive SCSI support' CONFIG_SCSI_PPA $CONFIG_SCSI dep_tristate 'PAS16 SCSI support' CONFIG_SCSI_PAS16 $CONFIG_SCSI dep_tristate 'Qlogic FAS SCSI support' CONFIG_SCSI_QLOGIC_FAS $CONFIG_SCSI if [ "$CONFIG_PCI" = "y" ]; then - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - dep_tristate 'Qlogic ISP SCSI support (EXPERIMENTAL)' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI - fi + dep_tristate 'Qlogic ISP SCSI support' CONFIG_SCSI_QLOGIC_ISP $CONFIG_SCSI fi dep_tristate 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE $CONFIG_SCSI dep_tristate 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 $CONFIG_SCSI diff -ur --new-file old/linux/drivers/scsi/Makefile new/linux/drivers/scsi/Makefile --- old/linux/drivers/scsi/Makefile Fri Jun 7 10:53:09 1996 +++ new/linux/drivers/scsi/Makefile Sat Jul 6 11:06:37 1996 @@ -263,6 +263,14 @@ endif endif +ifeq ($(CONFIG_SCSI_NCR53C8XX),y) +L_OBJS += ncr53c8xx.o +else + ifeq ($(CONFIG_SCSI_NCR53C8XX),m) + M_OBJS += ncr53c8xx.o + endif +endif + ifeq ($(CONFIG_SCSI_PAS16),y) L_OBJS += pas16.o else @@ -361,6 +369,9 @@ mv script.h 53c8xx_d.h mv scriptu.h 53c8xx_u.h rm fake.c + +ncr53c8xx.o : ncr53c8xx.c + $(CC) $(CFLAGS) -c ncr53c8xx.c scsi_mod.o: $(MX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o \ scsicam.o scsi_proc.o diff -ur --new-file old/linux/drivers/scsi/README.BusLogic new/linux/drivers/scsi/README.BusLogic --- old/linux/drivers/scsi/README.BusLogic Thu Jun 6 01:54:14 1996 +++ new/linux/drivers/scsi/README.BusLogic Wed Jul 17 20:22:13 1996 @@ -1,9 +1,9 @@ BusLogic MultiMaster SCSI Driver for Linux - Version 1.2.4 for Linux 1.2.13 - Version 2.0.4 for Linux 2.0.0 + Version 1.2.6 for Linux 1.2.13 + Version 2.0.6 for Linux 2.0.4 - 5 June 1996 + 17 July 1996 Leonard N. Zubkoff Dandelion Digital @@ -31,10 +31,11 @@ Linux kernel command line, allowing individual installations to tune driver performance and error recovery to their particular needs. -The most recent versions of this driver will always be available by anonymous -FTP from ftp.dandelion.com. While directory listings are not permitted, the -introductory banner displayed on anonymous FTP login will provide a list of the -driver versions and any other files that are available for retrieval. +The most recent versions of this driver will always be available from my Linux +Home Page at URL "http://www.dandelion.com/Linux/" and by anonymous FTP from +ftp.dandelion.com. While only limited FTP directory listings are permitted, +the introductory banner displayed on anonymous FTP login will provide a list of +the driver versions and any other files that are available for retrieval. Bug reports should be sent via electronic mail to "lnz@dandelion.com". Please include with the bug report the complete configuration messages reported by the @@ -295,9 +296,9 @@ during installation on a system with a flaky SCSI configuration. In cases of a marginal SCSI configuration it may also be beneficial to disable fast transfers and/or synchronous negotiation using AutoSCSI on "W" and "C" - series boards. Disconnect/reconnect may also be disabled for fast devices - such as disk drives, but should not be disabled for tape drives or other - devices where a single command may take over a second to execute. + series controllers. Disconnect/reconnect may also be disabled for fast + devices such as disk drives, but should not be disabled for tape drives or + other devices where a single command may take over a second to execute. "BusLogic=0,0,30" @@ -322,10 +323,10 @@ substantially impact performance. - INSTALLATION + INSTALLATION This distribution was prepared for Linux kernel version 1.2.13 -(BusLogic-1.2.4.tar.gz) or Linux kernel version 2.0.0 (BusLogic-2.0.4.tar.gz). +(BusLogic-1.2.6.tar.gz) or Linux kernel version 2.0.4 (BusLogic-2.0.6.tar.gz). Installation in later versions will probably be successful as well, though BusLogic.patch may not be required. Installation in earlier versions is not recommended. @@ -335,7 +336,7 @@ (substitute "1.2" or "2.0" for "x.y" in the tar command as appropriate): cd /usr/src - tar -xvzf BusLogic-x.y.4.tar.gz + tar -xvzf BusLogic-x.y.6.tar.gz mv README.* BusLogic.[ch] linux/drivers/scsi patch -p < BusLogic.patch (on Linux 1.2.13 only) patch -p < BusLogic.elf_patch (on Linux 1.2.13 ELF systems only) diff -ur --new-file old/linux/drivers/scsi/README.FlashPoint new/linux/drivers/scsi/README.FlashPoint --- old/linux/drivers/scsi/README.FlashPoint Sun Apr 14 10:21:08 1996 +++ new/linux/drivers/scsi/README.FlashPoint Wed Jul 17 20:22:13 1996 @@ -1,7 +1,11 @@ - ANNOUNCEMENT - BusLogic FlashPoint/BT-948 Upgrade Program - 1 February 1996 + ANNOUNCEMENT + BusLogic FlashPoint LT/BT-948 Upgrade Program + 1 February 1996 + + ADDITIONAL ANNOUNCEMENT + BusLogic FlashPoint LW/BT-958 Upgrade Program + 14 June 1996 Ever since its introduction last October, the BusLogic FlashPoint LT has been problematic for members of the Linux community, in that no Linux @@ -58,32 +62,39 @@ and has all the best features of both the BT-946C and FlashPoint LT, including smart termination and a flash PROM for easy firmware updates, and is of course compatible with the present Linux driver. The price for this -upgrade has been set at US $45, and the upgrade program will be -administered through BusLogic Technical Support, which can be reached by -electronic mail at techsup@buslogic.com, by Voice at +1 408 654-0760, or by -FAX at +1 408 492-1542. - -I was a beta test site for the BT-948 and versions 1.2.1 and 1.3.1 of my -BusLogic driver already include latent support for the BT-948. Additional -cosmetic support for the Ultra SCSI MultiMaster cards will be added in a -subsequent release. As a result of this cooperative testing process, -several firmware bugs were found and corrected (make sure you have firmware -version 5.05R or later). My heavily loaded Linux test system provided an -ideal environment for testing error recovery processes that are much more -rarely exercised in production systems, but are crucial to overall system -stability. It was especially convenient being able to work directly with -their firmware engineer in demonstrating the problems under control of the -firmware debugging environment; things sure have come a long way since the -last time I worked on firmware for an embedded system. I am presently -working on some performance testing and expect to have some data to report -in the not too distant future. +upgrade has been set at US $45 plus shipping and handling, and the upgrade +program will be administered through BusLogic Technical Support, which can +be reached by electronic mail at techsup@buslogic.com, by Voice at +1 408 +654-0760, or by FAX at +1 408 492-1542. + +As of 14 June 1996, the original BusLogic FlashPoint LT to BT-948 upgrade +program has now been extended to encompass the FlashPoint LW Wide Ultra +SCSI Host Adapter. Any Linux user worldwide may trade in their FlashPoint +LW (BT-950) for a BT-958 MultiMaster PCI Ultra SCSI Host Adapter. The +price for this upgrade has been set at US $65 plus shipping and handling. + +I was a beta test site for the BT-948/958, and versions 1.2.1 and 1.3.1 of +my BusLogic driver already included latent support for the BT-948/958. +Additional cosmetic support for the Ultra SCSI MultiMaster cards was added +subsequent releases. As a result of this cooperative testing process, +several firmware bugs were found and corrected. My heavily loaded Linux +test system provided an ideal environment for testing error recovery +processes that are much more rarely exercised in production systems, but +are crucial to overall system stability. It was especially convenient +being able to work directly with their firmware engineer in demonstrating +the problems under control of the firmware debugging environment; things +sure have come a long way since the last time I worked on firmware for an +embedded system. I am presently working on some performance testing and +expect to have some data to report in the not too distant future. BusLogic asked me to send this announcement since a large percentage of the questions regarding support for the FlashPoint have either been sent to me directly via email, or have appeared in the Linux newsgroups in which I participate. To summarize, BusLogic is offering Linux users an upgrade from the unsupported FlashPoint LT (BT-930) to the supported BT-948 for US -$45. Contact BusLogic Technical Support at techsup@buslogic.com or +1 408 +$45 plus shipping and handling, or from the unsupported FlashPoint LW +(BT-950) to the supported BT-958 for $65 plus shipping and handling. +Contact BusLogic Technical Support at techsup@buslogic.com or +1 408 654-0760 to take advantage of their offer. Leonard N. Zubkoff diff -ur --new-file old/linux/drivers/scsi/README.ncr53c8xx new/linux/drivers/scsi/README.ncr53c8xx --- old/linux/drivers/scsi/README.ncr53c8xx Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/scsi/README.ncr53c8xx Thu Jul 11 07:19:59 1996 @@ -0,0 +1,570 @@ +The linux NCR53C8XX driver README file + +Written by Gerard Roudier +21 Rue Carnot +95170 DEUIL LA BARRE - FRANCE + +12 June 1995 +=============================================================================== + +1. Introduction +2. Supported chips and SCSI features +3. Summary of other supported features +4. Memory mapped IO versus normal IO +5. Tagged command queueing +6. Parity checking +7. Profiling information +8. Control commands + 8.1 Set minimum synchronous period + 8.2 Set wide size + 8.3 Set maximum number of concurrent tagged commands + 8.4 Set order type for tagged command + 8.5 Set debug mode + 8.6 Clear profile counters +9. Configuration parameters +10. Some constants and flags of the ncr53c8xx.h header files +11. Provided files +12. Installation procedure for Linux version 1 +13. Installation procedure for Linux version 2 +14. Control commands under linux-1.2.13 +15. Known problems + 15.1 Tagged commands with Iomega Jaz device + 15.2 Tagged command queueing cannot be disabled at run time + +=============================================================================== + +1. Introduction + +This driver has been ported from FreeBSD to Linux and is currently +maintained by: + Gerard Roudier + +The original driver has been written for 386bsd and FreeBSD by + Wolfgang Stanglmeier + Stefan Esser + +You can find technical information about the NCR 8xx family in the PCI-HOWTO +written by Michael Will and in the SCSI-HOWTO written by Drew Eckhardt. + +Information about new chips is available at SYMBIOS web server: + http://www.symbios.com + +This short documentation only describes the features of the NCR53C8XX driver, +configuration parameters and control commands available through the proc scsi +file system read / write operations. + +This driver has been tested ok with linux/i386 and is currently untested +under linux/Alpha. If you intend to use this driver under linux/Alpha, just +try it first with read-only or mounted read-only devices. + +I am not a native speaker of English and there is probably lots of +mistakes in this README file. Any help will be welcome. + + +2. Supported chips and SCSI features + +The following features are supported for all chips: + + Synchronous negotiation + Disconnection + Tagged command queuing + Scsi parity checking + Master parity checking + +"Wide negotiation" is supported for chips that allow it. +The following table shows some characteristics of NCR 8xx family chips: + + On board Supported by Tested with +Chip SDMS BIOS Wide Ultra Scsi the driver the driver +---- --------- ---- ---------- ------------ ----------- +810 N N N Y Y +810A N N N Y Y +815 Y N N Y Y +825 Y Y N Y Y +825A Y Y N Y Not yet +875 Y Y Y(1) Y Not yet + +(1) Ultra scsi extensions will be supported in a future release of the + driver. + + +3. Summary of other supported features. + + Module: allow to load the driver + Memory mapped IO: increase performances + Profiling information: read operations from the proc scsi file system + Control commands: write operations to the proc scsi file system + Debugging information: written to syslog (expert only) + Scatter / gather + Shared interrupt + + +4. Memory mapped IO versus normal IO + +Memory mapped IO have less latency than normal IO. +Since linux-1.3.x, memory mapped IO is used rather than normal IO. +Memory mapped IO seems to works fine on most hardware configuration, but some +bad designed motherboards may break this feature. + +During initialisation phase, the driver first tries to use memory mapped io. +If nothing seems wrong, it will use memory mapped io. +If a flaw is detected, it will use normal io. + +However, it's possible that memory mapped io does not work properly and the +driver has not detected the problem. + +The configuration option CONFIG_SCSI_NCR53C8XX_IOMAPPED allow to force the +driver to use normal io in all cases. + + +5. Tagged command queueing + +Some scsi devices donnot support properly tagged command queuing. +A safe configuration can be to not enable tagged command queuing support at +boot-up, and to enable support of it with the control command "settags" +described further in this text. + +Once you are sure that all your devices support properly tagged command queuing, +you can enable it by default with the CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE +configuration option. + + +6. Parity checking + +The driver supports scsi parity checking and PCI bus master parity checking. +These features must be enabled in order to ensure safe data transfers. +However, some flawed devices or mother boards will have problems with +parity. You can disable parity by choosing first "CONFIG_EXPERIMENTAL". +Then, "make config" will allow to set the following configuration options: + + CONFIG_SCSI_NCR53C8XX_DISABLE_PARITY_CHECK (disable scsi parity checking) + CONFIG_SCSI_NCR53C8XX_DISABLE_MPARITY_CHECK (disable master parity checking) + + +7. Profiling information + +Profiling information are available through the proc scsi file system. +The device associated with a host has the following pathname: + /proc/scsi/ncr53c8xx/N (N=0,1,2 ....) + +Generally, only 1 board is used on hardware configuration, and the device is: + /proc/scsi/ncr53c8xx/0 + +However, if the driver has been made as module, the number of the host is +incremented each time the driver is loaded. + +In order to display profiling information, just enter: + cat /proc/scsi/ncr53c8xx/0 +and you will get something like the following text: + +------------------------------------------------------- +General information: + Chip NCR53C810, device id 0x1, revision id 0x2 + IO port address 0x6000, IRQ number 10 + Using memory mapped IO at virtual address 0x282c000 +Profiling information: + num_trans = 18014 + num_kbytes = 671314 + num_disc = 25763 + num_break = 1673 + num_int = 1685 + num_fly = 18038 + ms_setup = 4940 + ms_data = 369940 + ms_disc = 183090 + ms_post = 1320 +------------------------------------------------------- + +General information is easy to understand. The device id and the +revision id identify the scsi chip as follows: + +Chip Device id Revision Id +---- --------- ----------- +810 0x1 < 0x10 +810A 0x1 >= 0x10 +815 0x4 +825 0x3 < 0x10 +860 0x6 +825A 0x3 >= 0x10 +875 0xf + +The profiling information is updated upon completion of scsi commands. +The data structure is allocated and zeroed when the host adapter is +attached. So, if the driver is a module, the profile counters are cleared each +time the driver is loaded. +The "clearprof" command allow to clear these counters at any time. + +The following counters are available: +("num" prefix means "number of", "ms" means milli-seconds) + +num_trans + Number of completed commands + Example above: 18014 completed commands + +num_kbytes + Number of kbytes transferred + Example above: 671 MB transferred + +num_disc + Number of scsi disconnections + Example above: 25763 scsi disconnections + +num_break + number of script interruptions (phase mismatch) + Example above: 1673 script interruptions + +num_int + Number of interrupts other than "on the fly" + Example above: 1685 interruptions not "on the fly" + +num_fly + Number of interrupts "on the fly" + Example above: 18038 interruptions "on the fly" + +ms_setup + Elapsed time for scsi commands setups + Example above: 4.94 seconds + +ms_data + Elapsed time for data transfers + Example above: 369.94 seconds spent for data transfer + +ms_disc + Elapsed time for scsi disconnections + Example above: 183.09 seconds spent disconnected + +ms_post + Elapsed time for command post processing + (time from scsi status get to command completion call) + Example above: 1.32 seconds spent for post processing + +Due to the 1/100 second tick of the system clock, "ms_post" time may be +wrong. + +In the example above, we got 18038 interrupts "on the fly" and only 1673 script +breaks probably due to disconnections inside a segment of the scatter list. +It is an excellent result due to the fact that the driver tries to use small +data segments (512) for the scatter list. The CPU load of this rescatter process +is acceptable. Unlike other scsi processors, NCR53C8XX controllers do not need +large data chunks in order to get better performances, and it seems that it +is the opposite. +The scatter/gather algorithm of the middle scsi driver is not optimal for +NCR scsi processors and should be tunable according to host type. + +You can tune the "wished" segment size for the scatterlist by changing the +following "define" in the file ncr53c8xx.h. +Use only power of 2 greater than 512 (1024, 2048 or 4096). + +SCSI_NCR_SEGMENT_SIZE (default: 512) + + +8. Control commands + +Control commands can be sent to the driver with write operations to the +proc scsi file system. The generic command syntax is the following: + + echo " " >/proc/scsi/ncr53c8xx/0 + (assumes controller number is 0) + +Available commands: + +8.1 Set minimum synchronous period + + setsync + + target: target number + period: minimum synchronous period in nano-seconds. + Maximum speed = 1000/(4*period) MB/second + + Specify a period of 255, to force asynchronous transfer mode. + +8.2 Set wide size + + setwide + + target: target number + size: 0=8 bits, 1=16bits + +8.3 Set maximum number of concurrent tagged commands + + settags + + target: target number + tags: number of concurrent tagged commands + must not be greater than SCSI_NCR_MAX_TAGS (default: 4) + must not be lower that 1 (see: known problems) + +8.4 Set order type for tagged command + + setorder + + order: 3 possible values: + simple: use SIMPLE TAG for all operations (read and write) + ordered: use ORDERED TAG for all operations + default: use default tag type, + SIMPLE TAG for read operations + ORDERED TAG for write operations + + +8.5 Set debug mode + + setdebug + + Available debug flags: + alloc: print infos about memory allocations (ccb, lcb) + queue: print infos about insertions into the command start queue + result: print sense data on CHECK CONDITION status + scatter: print infos about the scatter process + scripts: print infos about the script binding process + tiny: print minimal debugging information + timing: print timing information of the ncr chip. + nego: print information about scsi negotiations + phase: print information on script interruptions + + +8.6 Clear profile counters + + clearprof + + The profile counters are automatically cleared when the amount of data + transfered reach 1000 GB in order to avoid overflow. + The "clearprof" command allow to clear these counters at any time. + + +9. Configuration parameters + +If the firmware of all your devices is perfect enough, all the features +supported by the driver can be enabled at start-up. +However, if only one has a flaw for some scsi feature, you can disable the +support by the driver of this feature at linux start-up and enable this +feature after boot-up only for devices that support it safely. + +CONFIG_SCSI_NCR53C8XX_IOMAPPED (default answer: n) + Answer "y" if you suspect your mother board to not allow memory mapped IO. + May slow down a little performances. + +CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE (default answer: n) + Answer "y" if you are sure that all your scsi devices that are able to + accept tagged commands will proceed safely. + +CONFIG_SCSI_NCR53C8XX_FORCE_ASYNCHRONOUS (default answer: n) + This option allow to force asynchronous transfer mode for all scsi devices. + +CONFIG_SCSI_NCR53C8XX_FORCE_SYNC_NEGO (default answer: n) + Force synchronous negotiation for all scsi-2 devices. + Some scsi-2 devices do not report this feature in byte 7 of inquiry + response and however support it properly (TAMARACK scanners for example). + +CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT (default and only reasonnable answer: n) + If you suspect a device of yours to not support properly disconnections, + you can answer "y". Then, all scsi devices will never disconnect the bus + even while long scsi operations. + + +10. Some constants and flags of the ncr53c8xx.h header files + +Some of these are defined from the configuration parameters. +To change other "defines", you must edit the header file. +Do that only if you know what you are doing. + +SCSI_NCR_IOMAPPED (default: not defined) + If defined, normal IO is forced. + +SCSI_NCR_SHARE_IRQ (default: defined) + If defined, request shared irq. + +SCSI_NCR_MAX_TAGS (default: 4) + Maximum number of simultaneous tagged commands to a device. + Can be changed by "settags " + +SCSI_NCR_ALWAYS_SIMPLE_TAG (default: defined) + Use SIMPLE TAG for read and write commands + Can be changed by "setorder " + +SCSI_NCR_TAGGED_QUEUE_DISABLED (default: defined) + If defined, tagged command queuing is disable at start-up. + Can be changed by "settags " + +SCSI_NCR_NO_DISCONNECT (default: not defined) + If defined, targets are not allowed to disconnect. + +SCSI_NCR_FORCE_SYNC_NEGO (default: not defined) + If defined, synchronous negotiation is tried for all scsi-2 devices. + Can be changed by "setsync " + +SCSI_NCR_DISABLE_MPARITY_CHECK (default: not defined) + If defined, master parity checking is disabled. + +SCSI_NCR_DISABLE_PARITY_CHECK (default: not defined) + If defined, scsi parity checking is disabled. + +SCSI_NCR_PROFILE (default: defined) + If defined, profile information are gathered + +SCSI_NCR_MAX_SCATTER (default: 128) + Scatter list size of the driver ccb. + +SCSI_NCR_SEGMENT_SIZE (default: 512) + If defined, the driver try to use scatter segments of this size. + If not defined, the Linux scatter list is used as is. + +SCSI_NCR_MAX_TARGET (default: 16) + Max number of target per host. + +SCSI_NCR_MAX_HOST (default: 2) + Max number of host controllers. + +SCSI_NCR_SETTLE_TIME (default: 2) + Number of seconds the driver wait after reset. + +SCSI_NCR_TIMEOUT_ALERT (default: 3) + If a pending command will time out after this amount of seconds, + an ordered tag is used for the next command. + Avoid timeouts for unordered tagged commands. + +SCSI_NCR_CAN_QUEUE (default: 7*SCSI_NCR_MAX_TAGS) + Max number of commands that can be queued to a host. + +SCSI_NCR_CMD_PER_LUN (default: SCSI_NCR_MAX_TAGS) + Max number of commands queued to a host for a device. + +SCSI_NCR_SG_TABLESIZE (default: SCSI_NCR_MAX_SCATTER-1) + Max size of the Linux scatter/gather list. + +SCSI_NCR_MAX_LUN (default: 8) + Max number of luns per target + + +11. Provided files + +Driver and common files: + + README.ncr53c8xx : this file + ChangeLog.ncr53c8xx : change log + ncr53c8xx.h : definitions + ncr53c8xx.c : the driver code + scsitag.c : command tool to enable tagged queue + conf.modules : sample of /etc/conf.modules + +Installation procedure 1 replacing the standard NCR53c7,8xx driver: + + Install.ncr53c8xx : installation script + Uninstall.ncr53c8xx : uninstallation script + 53c7,8xx.h : included by hosts.c, override the standard driver + + Patch-1.2.13.ncr53c8xx : patch for linux-1.2.13 + Patch-1.3.45-49.ncr53c8xx : patch for linux-1.3.45 to linux-1.3.49 + Patch-1.3.50-100.ncr53c8xx : patch for linux-1.3.50 to linux-1.3.100 + +Installation procedure 2 adding the driver to the kernel tree: + + Install2.ncr53c8xx : installation script + + Patch2-2.0.0-1.ncr53c8xx : patch for linux-2.0.0 and linux-2.0.1 + Patch2-Current.ncr53c8xx : patch used for sub-levels > 1 + +Prior to installing the driver, you must untar the distribution, as follow: + + mkdir ncrB2L + cd ncrB2L + tar zxvf ncrBsd2Linux-1.12a-src.tar.gz + + +12. Installation procedure for Linux version 1 + +This install script only supports linux-1.2.13 and linux-1.3.45 to 1.3.100. + +This procedure just move the standard driver files to SAVE_53 sub-directory +of linux/drivers/scsi, copies the drivers file to that directory and patches +the scsi Makefile. +The standard driver can be restored with Uninstall.ncr53c8xx + + If your linux directory is at the standard location + "/usr/src/linux", just enter: + Install.ncr53c8xx + + Else enter: + Install.ncr53c8xx + + Make the kernel: + Change to linux source directory + Configure with 53c7,8xx support (Y or m) for Install.ncr53c8xx + Make dependancies + Make the kernel (use make zdisk first) + Make and install modules if you have configured with 'm' + + Notes: + Since release 1.3.90, additionnal configuation parameters + have been added for the standard NCR driver. + Just reply Y or N as you want to these questions; + The NCR53C8XX driver ignore those parameters. + + If you prefer the standard NCR driver of Linux: + just enter: + Uninstall.ncr53c8xx + or + Uninstall.ncr53c8xx + if your linux root is not /usr/src/linux. + + +13. Installation procedure for Linux version 2 + +This procedure add the driver to the kernel tree. +Using "make config" you can choose between the standard driver and the BSD one. +It is possible to configure the both drivers as module and to switch from one +to the other at run time. +Take care to unload the current driver module before loading the other one. + + If your linux directory is at the standard location + "/usr/src/linux", just enter: + Install2.ncr53c8xx + + Else enter: + Install2.ncr53c8xx + + Make the kernel: + Change to linux source directory + Configure with NCR53C8XX support (Y or m) + Make dependancies + Make the kernel (use make zdisk first) + Make and install modules if you have configured with 'm' + + +14. Control commands under linux-1.2.13 + +Profile data and control commands using the proc scsi file system are not +available for linux-1.2.13. +The only control command available is "scsitag" which allows to enable +tagged command queuing support after linux boot-up. + +Tagged command queueing is disabled by default at system startup. + +You can enable tagged queue per device with the following command: + scsitag device_name (ex: scsitag /dev/sda) + +Use "cc -o scsitag scsitag.c" to create the "scsitag" executable. + + +15. Known problems + +15.1 Tagged commands with Iomega Jaz device + +I never tried such devices, however it has been reported to me the following: +This device is capable of Tagged command queuing. However while spinning up, +it rejects Tagged commands. This behaviour is conforms to 6.8.2 of scsi-2 +specifications. The current behaviour of the driver in that situation is not +satisfying. So do not enable Tagged command queuing for devices that are able +to spin down. +The other problems that may appear are timeouts. The only way to avoid timeouts +seems to edit linux/drivers/scsi/sd.c and to increase the current timeout +values. + +15.2 Tagged command queuing cannot be disabled at run time + +Once Tagged command queuing has been enabled, the driver will not allow to +disable this feature ("settags 0" is not supported). +This problem is due to some limitations of the code added to the Linux version +of the driver. + +=============================================================================== +End of NCR53C8XX driver README file diff -ur --new-file old/linux/drivers/scsi/README.st new/linux/drivers/scsi/README.st --- old/linux/drivers/scsi/README.st Sun May 5 07:51:13 1996 +++ new/linux/drivers/scsi/README.st Mon Jul 1 06:08:27 1996 @@ -1,5 +1,8 @@ This file contains brief information about the SCSI tape driver. -Last modified: Wed May 1 11:51:35 1996 by root@kai.makisara.fi +The driver is currently maintained by Kai M{kisara (email +Kai.Makisara@metla.fi) + +Last modified: Sun Jun 30 15:47:14 1996 by root@kai.makisara.fi BASICS @@ -85,13 +88,15 @@ compile time and/or at run time (via ioctl): Buffering of data across write calls in fixed block mode (define -ST_BUFFER_WRITES). This should be disabled if reliable detection of -end of medium (EOM) for fixed block mode is desired. +ST_BUFFER_WRITES). Asynchronous writing. Writing the buffer contents to the tape is started and the write call returns immediately. The status is checked -at the next tape operation. Should not used if reliable EOM detection -is desired. +at the next tape operation. + +Buffered writes and asynchronous writes may in some rare cases cause +problems in multivolume operations if there is not enough space after +the early-warning mark to flush the driver buffer. Read ahead for fixed block mode (ST_READ_AHEAD). Filling the buffer is attempted even if the user does not want to get all of the data at @@ -187,7 +192,8 @@ control of compression. Some drives (like the Exabytes) use density codes for compression control. Some drives use another mode page but this page has not been implemented in the - driver. + driver. Some drives without compression capability will accept + any compression mode without error. MTSETPART Moves the tape to the partition given by the argument at the next tape operation. The block at which the tape is positioned is the block where the tape was previously positioned in the @@ -310,5 +316,3 @@ time or the MT_ST_CAN_BSR bit is set for the drive with an ioctl. (The driver always backs over a filemark crossed by read ahead if the user does not request data that far.) - -Kai M{kisara diff -ur --new-file old/linux/drivers/scsi/advansys.c new/linux/drivers/scsi/advansys.c --- old/linux/drivers/scsi/advansys.c Fri May 10 06:55:36 1996 +++ new/linux/drivers/scsi/advansys.c Wed Aug 14 08:59:04 1996 @@ -1,21 +1,26 @@ -/* $Id: advansys.c,v 1.14 1996/05/10 00:26:31 bobf Exp bobf $ */ +/* $Id: advansys.c,v 1.15 1996/08/12 17:20:23 bobf Exp bobf $ */ /* * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters * * Copyright (c) 1995-1996 Advanced System Products, Inc. * All Rights Reserved. * - * This driver may be modified and freely distributed provided that - * the above copyright message and this comment are included in the - * distribution. The latest version of this driver is available at - * the AdvanSys FTP and BBS sites listed below. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that redistributions of source + * code retain the above copyright notice and this comment without + * modification. + * + * The latest version of this driver is available at the AdvanSys + * FTP and BBS sites listed below. * * Please send questions, comments, bug reports to: * bobf@advansys.com (Bob Frey) */ -/* The driver has been tested with Linux v1.2.13 and v1.3.57 kernels. */ -#define ASC_VERSION "1.4" /* AdvanSys Driver Version */ +/* + * The driver has been run with the v1.2.13, v1.3.57, and v2.0.11 kernels. + */ +#define ASC_VERSION "1.5" /* AdvanSys Driver Version */ /* @@ -23,7 +28,7 @@ A. Adapters Supported by this Driver B. Linux v1.2.X - Directions for Adding the AdvanSys Driver - C. Linux v1.3.X - Directions for Adding the AdvanSys Driver + C. Linux v1.3.X, v2.X.X - Directions for Adding the AdvanSys Driver D. Source Comments E. Driver Compile Time Options and Debugging F. Driver LILO Option @@ -32,7 +37,6 @@ I. Credits J. AdvanSys Contact Information - A. Adapters Supported by this Driver AdvanSys (Advanced System Products, Inc.) manufactures the following @@ -41,35 +45,42 @@ The CDB counts below indicate the number of SCSI CDB (Command Descriptor Block) requests that can be stored in the RISC chip - cache and board LRAM. The driver detect routine will display the - number of CDBs available for each adapter detected. This value - can be lowered in the BIOS by changing the 'Host Queue Size' - adapter setting. + cache and board LRAM. A CDB is a single SCSI command. The driver + detect routine will display the number of CDBs available for each + adapter detected. This value can be lowered in the BIOS by changing + the 'Host Queue Size' adapter setting. Connectivity Products: - ABP920 - Bus-Master PCI 16 CDB - ABP930 - Bus-Master PCI 16 CDB - ABP5140 - Bus-Master PnP ISA 16 CDB - + ABP510/5150 - Bus-Master ISA (240 CDB) (Footnote 1) + ABP5140 - Bus-Master ISA PnP (16 CDB) (Footnote 1) + ABP5142 - Bus-Master ISA PnP with floppy (16 CDB) + ABP920 - Bus-Master PCI (16 CDB) + ABP930 - Bus-Master PCI (16 CDB) + ABP960 - Bus-Master PCI MAC/PC (16 CDB) (Footnote 2) + Single Channel Products: - ABP542 - Bus-Master ISA 240 CDB - ABP5150 - Bus-Master ISA 240 CDB * - ABP742 - Bus-Master EISA 240 CDB - ABP842 - Bus-Master VL 240 CDB - ABP940 - Bus-Master PCI 240 CDB - + ABP542 - Bus-Master ISA with floppy (240 CDB) + ABP742 - Bus-Master EISA (240 CDB) + ABP842 - Bus-Master VL (240 CDB) + ABP940 - Bus-Master PCI (240 CDB) + ABP940U - Bus-Master PCI Ultra (240 CDB) + ABP970 - Bus-Master PCI MAC/PC (240 CDB) + Dual Channel Products: - ABP950 - Dual Channel Bus-Master PCI 240 CDB Per Channel - ABP852 - Dual Channel Bus-Master VL 240 CDB Per Channel - ABP752 - Dual Channel Bus-Master EISA 240 CDB Per Channel - - * This board is shipped by HP with the 4020i CD-R drive. It has - no BIOS so it cannot control a boot device, but it can control - any secondary devices. - + ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel) + ABP852 - Dual Channel Bus-Master VL (240 CDB Per Channel) + ABP950 - Dual Channel Bus-Master PCI (240 CDB Per Channel) + + Footnotes: + 1. These boards have been shipped by HP with the 4020i CD-R drive. + They have no BIOS so they cannot control a boot device, but they + can control secondary devices. + + 2. This board has been shipped by Iomega with the Jaz Jet drive. + B. Linux v1.2.X - Directions for Adding the AdvanSys Driver - These directions apply to v1.2.1. For versions that follow v1.2.1 + These directions apply to v1.2.13. For versions that follow v1.2.13. but precede v1.3.57 some of the changes for Linux v1.3.X listed below may need to be modified or included. @@ -137,7 +148,7 @@ 'make modules_install'. Use 'insmod' and 'rmmod' to install and remove advansys.o. - C. Linux v1.3.X - Directions for Adding the AdvanSys Driver + C. Linux v1.3.X, v2.X.X - Directions for Adding the AdvanSys Driver These directions apply to v1.3.57. For versions that precede v1.3.57 some of these changes may need to be modified or eliminated. Beginning @@ -217,8 +228,7 @@ --- Driver Options --- Asc Library Constants and Macros --- Debugging Header - --- Driver Constants - --- Driver Macros + --- Driver Constants and Macros --- Driver Structures --- Driver Data --- Driver Function Prototypes @@ -269,7 +279,6 @@ insmod advansys.o asc_dbglvl=1 - Debugging Message Levels: 0: Errors Only 1: High-Level Tracing @@ -287,19 +296,24 @@ I found that increasing LOG_BUF_LEN to 40960 in kernel/printk.c prevents most level 1 debug messages from being lost. - 2. ADVANSYS_STATS - enable statistics and tracing + 2. ADVANSYS_STATS - enable statistics - For Linux v1.2.X if ADVANSYS_STATS_1_2_PRINT is defined every - 10,000 I/O operations the driver will print statistics to the - console. This value can be changed by modifying the constant - used in advansys_queuecommand(). ADVANSYS_STATS_1_2_PRINT is - off by default. + Statistics are maintained on a per adapter basis. Driver entry + point call counts and tranfer size counts are maintained. + Statistics are only available for kernels greater than or equal + to v1.3.0 with the CONFIG_PROC_FS (/proc) file system configured. + + AdvanSys SCSI adapter files have the following path name format: + + /proc/scsi/advansys/[0-(ASC_NUM_BOARD_SUPPORTED-1)] + + This information can be displayed with cat. For example: - For Linux v1.3.X statistics can be accessed by reading the - /proc/scsi/advansys/[0-(ASC_NUM_BOARD_SUPPORTED-1)] files. + cat /proc/scsi/advansys/0 + + When ADVANSYS_STATS is not defined the AdvanSys /proc files only + contain adapter and device configuration information. - Note: these statistics are currently maintained on a global driver - basis and not per board. F. Driver LILO Option @@ -334,14 +348,14 @@ G. Release History - 12/23/95 BETA-1.0: + BETA-1.0 (12/23/95): First Release - 12/28/95 BETA-1.1: + BETA-1.1 (12/28/95): 1. Prevent advansys_detect() from being called twice. 2. Add LILO 0xdeb[0-f] option to set 'asc_dbglvl'. - 1/12/96 1.2: + 1.2 (1/12/96): 1. Prevent re-entrancy in the interrupt handler which resulted in the driver hanging Linux. 2. Fix problem that prevented ABP-940 cards from being @@ -350,7 +364,7 @@ 4. Fix check condition return status. 5. Add conditionally compiled code for Linux v1.3.X. - 2/23/96 1.3: + 1.3 (2/23/96): 1. Fix problem in advansys_biosparam() that resulted in the wrong drive geometry being returned for drives > 1GB with extended translation enabled. @@ -360,7 +374,7 @@ 5. Try to fix problem with handling resets by increasing their timeout value. - 5/8/96 1.4: + 1.4 (5/8/96): 1. Change definitions to eliminate conflicts with other subsystems. 2. Add versioning code for the shared interrupt changes. 3. Eliminate problem in asc_rmqueue() with iterating after removing @@ -369,18 +383,29 @@ Issues" section. This problem was isolated and fixed in the mid-level SCSI driver. - H. Known Problems or Issues + 1.5 (8/8/96): + 1. Add support for ABP-940U (PCI Ultra) adapter. + 2. Add support for IRQ sharing by setting the SA_SHIRQ flag for + request_irq and supplying a dev_id pointer to both request_irq() + and free_irq(). + 3. In AscSearchIOPortAddr11() restore a call to check_region() which + should be used before any I/O port probing. + 4. Fix bug in asc_prt_hex() which resulted in the displaying + the wrong data. + 5. Incorporate miscellaneous Asc Library bug fixes and new microcode. + 6. Change driver versioning to be specific to each Linux sub-level. + 7. Change statistics gathering to be per adapter instead of global + to the driver. + 8. Add more information and statistics to the adapter /proc file: + /proc/scsi/advansys[0...]. + 9. Remove 'cmd_per_lun' from the "Known Problems or Issues" list. + This problem has been addressed with the SCSI mid-level changes + made in v1.3.89. The advansys_select_queue_depths() function + was added for the v1.3.89 changes. - 1. The setting for 'cmd_per_lun' needs to be changed. It is currently - less then what the AdvanSys boards can queue. Because the target and - mid-level Linux drivers base memory allocation on 'cmd_per_lun' (as - well as 'sg_tablesize') memory use gets out of hand with a large - 'cmd_per_lun'. 'cmd_per_lun' should be per device instead of per - adapter. When the driver is compiled as a loadable module both - 'cmd_per_lun' and 'sg_tablesize' are tuned down to try to prevent - memory allocation errors. + H. Known Problems or Issues - 2. For the first scsi command sent to a device the driver increases + 1. For the first scsi command sent to a device the driver increases the timeout value. This gives the driver more time to perform its own initialization for the board and each device. The timeout value is only changed on the first scsi command for each device @@ -389,28 +414,26 @@ I. Credits Nathan Hartwell provided the directions and - and basis for the Linux v1.3.X changes which were included in the + basis for the Linux v1.3.X changes which were included in the 1.2 release. - Thomas E Zerucha pointed out the bug - in advansys_biosparam() which was fixed the 1.3 release. + Thomas E Zerucha pointed out a bug + in advansys_biosparam() which was fixed in the 1.3 release. J. AdvanSys Contact Information Mail: Advanced System Products, Inc. 1150 Ringwood Court - San Jose, CA 95131 USA + San Jose, CA 95131 Operator: 1-408-383-9400 FAX: 1-408-383-9612 - Tech Support: 1-800-525-7440 - BBS: 1-408-383-9540 (9600,N,8,1) + Tech Support: 1-800-525-7440/1-408-467-2930 + BBS: 1-408-383-9540 (14400,N,8,1) Interactive FAX: 1-408-383-9753 - Customer Direct Sales: 1-800-883-1099 + Customer Direct Sales: 1-800-883-1099/1-408-383-5777 Tech Support E-Mail: support@advansys.com - Linux Support E-Mail: bobf@advansys.com FTP Site: ftp.advansys.com (login: anonymous) Web Site: http://www.advansys.com - */ @@ -418,30 +441,23 @@ * --- Linux Version */ -/* - * The driver can be used in Linux v1.2.X or v1.3.X. - */ -#if !defined(LINUX_1_2) && !defined(LINUX_1_3) +/* Convert Linux Version, Patch-level, Sub-level to LINUX_VERSION_CODE. */ +#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S)) + #ifndef LINUX_VERSION_CODE #include #endif /* LINUX_VERSION_CODE */ -#if LINUX_VERSION_CODE > 65536 + 3 * 256 -#define LINUX_1_3 -#else /* LINUX_VERSION_CODE */ -#define LINUX_1_2 -#endif /* LINUX_VERSION_CODE */ -#endif /* !defined(LINUX_1_2) && !defined(LINUX_1_3) */ /* * --- Linux Include Files */ -#ifdef LINUX_1_3 +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) #ifdef MODULE #include #endif /* MODULE */ -#endif /* LINUX_1_3 */ +#endif /* version >= v1.3.0 */ #include #include #include @@ -450,18 +466,18 @@ #include #include #include -#ifdef LINUX_1_3 +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) #include -#endif /* LINUX_1_3 */ +#endif /* version >= v1.3.0 */ #include #include #include -#ifdef LINUX_1_2 +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) #include "../block/blk.h" -#else /* LINUX_1_3 */ +#else /* version >= v1.3.0 */ #include #include -#endif /* LINUX_1_3 */ +#endif /* version >= v1.3.0 */ #include "scsi.h" #include "hosts.h" #include "sd.h" @@ -471,11 +487,17 @@ /* * --- Driver Options */ -#define ADVANSYS_DEBUG /* Enable for debugging and assertions. */ -#define ADVANSYS_STATS /* Enable for statistics and tracing. */ -#ifdef LINUX_1_2 -#undef ADVANSYS_STATS_1_2_PRINT /* Enable to print statistics to console. */ -#endif /* LINUX_1_2 */ + +#define ADVANSYS_DEBUG /* Enable assertions and tracing. */ +/* + * Because of no /proc to display them, statistics are disabled + * for version prior to v1.3.0. + */ +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) +#undef ADVANSYS_STATS /* Disable statistics */ +#else /* version >= v1.3.0 */ +#define ADVANSYS_STATS /* Enable statistics. */ +#endif /* version >= v1.3.0 */ /* @@ -483,297 +505,236 @@ */ #define ASC_LIB_VERSION_MAJOR 1 -#define ASC_LIB_VERSION_MINOR 16 -#define ASC_LIB_SERIAL_NUMBER 53 +#define ASC_LIB_VERSION_MINOR 21 +#define ASC_LIB_SERIAL_NUMBER 88 typedef unsigned char uchar; #ifndef NULL #define NULL (0) #endif - #ifndef TRUE #define TRUE (1) #endif - #ifndef FALSE #define FALSE (0) #endif - #define REG register - #define rchar REG __s8 #define rshort REG __s16 #define rint REG __s32 #define rlong REG __s32 - #define ruchar REG __u8 #define rushort REG __u16 #define ruint REG __u32 #define rulong REG __u32 - #define NULLPTR ( void *)0 #define FNULLPTR ( void dosfar *)0UL #define EOF (-1) #define EOS '\0' #define ERR (-1) -#define UB_ERR (__u8)(0xFF) -#define UW_ERR (__u16)(0xFFFF) -#define UL_ERR (__u32)(0xFFFFFFFFUL) - -#define iseven_word( val ) ( ( ( ( __u16 )val) & ( __u16 )0x0001 ) == 0 ) -#define isodd_word( val ) ( ( ( ( __u16 )val) & ( __u16 )0x0001 ) != 0 ) -#define toeven_word( val ) ( ( ( __u16 )val ) & ( __u16 )0xFFFE ) - -#define biton( val, bits ) ((( __u16 )( val >> bits ) & (__u16)0x0001 ) != 0 ) -#define bitoff( val, bits ) ((( __u16 )( val >> bits ) & (__u16)0x0001 ) == 0 ) -#define lbiton( val, bits ) ((( __u32 )( val >> bits ) & (__u32)0x00000001UL ) != 0 ) -#define lbitoff( val, bits ) ((( __u32 )( val >> bits ) & (__u32)0x00000001UL ) == 0 ) - +#define UB_ERR (uchar)(0xFF) +#define UW_ERR (uint)(0xFFFF) +#define UL_ERR (ulong)(0xFFFFFFFFUL) +#define iseven_word( val ) ( ( ( ( uint )val) & ( uint )0x0001 ) == 0 ) +#define isodd_word( val ) ( ( ( ( uint )val) & ( uint )0x0001 ) != 0 ) +#define toeven_word( val ) ( ( ( uint )val ) & ( uint )0xFFFE ) +#define biton( val, bits ) ((( uint )( val >> bits ) & (uint)0x0001 ) != 0 ) +#define bitoff( val, bits ) ((( uint )( val >> bits ) & (uint)0x0001 ) == 0 ) +#define lbiton( val, bits ) ((( ulong )( val >> bits ) & (ulong)0x00000001UL ) != 0 ) +#define lbitoff( val, bits ) ((( ulong )( val >> bits ) & (ulong)0x00000001UL ) == 0 ) #define absh( val ) ( ( val ) < 0 ? -( val ) : ( val ) ) - #define swapbyte( ch ) ( ( ( (ch) << 4 ) | ( (ch) >> 4 ) ) ) - #ifndef GBYTE #define GBYTE (0x40000000UL) #endif - #ifndef MBYTE #define MBYTE (0x100000UL) #endif - #ifndef KBYTE #define KBYTE (0x400) #endif - #define HI_BYTE(x) ( *( ( __u8 *)(&x)+1 ) ) #define LO_BYTE(x) ( *( ( __u8 *)&x ) ) - #define HI_WORD(x) ( *( ( __u16 *)(&x)+1 ) ) #define LO_WORD(x) ( *( ( __u16 *)&x ) ) - #ifndef MAKEWORD #define MAKEWORD(lo, hi) ((__u16) (((__u16) lo) | ((__u16) hi << 8))) #endif - #ifndef MAKELONG #define MAKELONG(lo, hi) ((__u32) (((__u32) lo) | ((__u32) hi << 16))) #endif - #define SwapWords(dWord) ((__u32) ((dWord >> 16) | (dWord << 16))) #define SwapBytes(word) ((__u16) ((word >> 8) | (word << 8))) - -#define BigToLittle(dWord) \ - ((__u32) (SwapWords(MAKELONG(SwapBytes(LO_WORD(dWord)), SwapBytes(HI_WORD(dWord)))))) +#define BigToLittle(dWord) ((__u32) (SwapWords(MAKELONG(SwapBytes(LO_WORD(dWord)), SwapBytes(HI_WORD(dWord)))))) #define LittleToBig(dWord) BigToLittle(dWord) +#define AscPCICmdRegBits_BusMastering 0x0007 +#define AscPCIConfigVendorIDRegister 0x0000 +#define AscPCIConfigDeviceIDRegister 0x0002 +#define AscPCIConfigCommandRegister 0x0004 +#define AscPCIConfigStatusRegister 0x0006 +#define AscPCIConfigCacheSize 0x000C +#define AscPCIConfigLatencyTimer 0x000D +#define AscPCIIOBaseRegister 0x0010 +#define ASC_PCI_ID2BUS( id ) ((id) & 0xFF) +#define ASC_PCI_ID2DEV( id ) (((id) >> 11) & 0x1F) +#define ASC_PCI_ID2FUNC( id ) (((id) >> 8) & 0x7) +#define ASC_PCI_MKID( bus, dev, func ) ((((dev) & 0x1F) << 11) | (((func) & 0x7) << 8) | ((bus) & 0xFF)) #define Lptr #define dosfar #define far -#define PortAddr unsigned short -#define Ptr2Func ulong - -#define inp(port) inb(port) -#define inpw(port) inw(port) +#define PortAddr unsigned short /* port address size */ +#define Ptr2Func ulong +#define inp(port) inb(port) +#define inpw(port) inw(port) +#define inpl(port) inl(port) #define outp(port, byte) outb((byte), (port)) #define outpw(port, word) outw((word), (port)) - +#define outpl(port, long) outl((long), (port)) #define ASC_MAX_SG_QUEUE 5 #define ASC_MAX_SG_LIST (1 + ((ASC_SG_LIST_PER_Q) * (ASC_MAX_SG_QUEUE))) #define CC_INIT_INQ_DISPLAY FALSE - #define CC_CLEAR_LRAM_SRB_PTR FALSE #define CC_VERIFY_LRAM_COPY FALSE - #define CC_DEBUG_SG_LIST FALSE #define CC_FAST_STRING_IO FALSE - #define CC_WRITE_IO_COUNT FALSE #define CC_CLEAR_DMA_REMAIN FALSE - #define CC_DISABLE_PCI_PARITY_INT TRUE - #define CC_LINK_BUSY_Q FALSE - -#define CC_TARGET_MODE FALSE - -#define CC_SCAM FALSE - #define CC_LITTLE_ENDIAN_HOST TRUE - -#ifndef CC_TEST_LRAM_ENDIAN - -#if CC_LITTLE_ENDIAN_HOST -#define CC_TEST_LRAM_ENDIAN FALSE -#else -#define CC_TEST_LRAM_ENDIAN TRUE -#endif - -#endif - #define CC_STRUCT_ALIGNED TRUE - -#define CC_MEMORY_MAPPED_IO FALSE - -#ifndef CC_TARGET_MODE -#define CC_TARGET_MODE FALSE -#endif - -#ifndef CC_STRUCT_ALIGNED -#define CC_STRUCT_ALIGNED FALSE -#endif - -#ifndef CC_LITTLE_ENDIAN_HOST -#define CC_LITTLE_ENDIAN_HOST TRUE -#endif - -#if !CC_LITTLE_ENDIAN_HOST - -#ifndef CC_TEST_LRAM_ENDIAN -#define CC_TEST_LRAM_ENDIAN TRUE -#endif - -#endif - -#ifndef CC_MEMORY_MAPPED_IO #define CC_MEMORY_MAPPED_IO FALSE -#endif - -#ifndef CC_WRITE_IO_COUNT -#define CC_WRITE_IO_COUNT FALSE -#endif - -#ifndef CC_CLEAR_DMA_REMAIN -#define CC_CLEAR_DMA_REMAIN FALSE -#endif +#define CC_INCLUDE_EEP_CONFIG TRUE +#define CC_PCI_ULTRA TRUE +#define CC_INIT_TARGET_READ_CAPACITY TRUE +#define CC_INIT_TARGET_TEST_UNIT_READY TRUE +#define CC_ASC_SCSI_Q_USRDEF FALSE +#define CC_ASC_SCSI_REQ_Q_USRDEF FALSE +#define CC_ASCISR_CHECK_INT_PENDING TRUE +#define CC_CHK_FIX_EEP_CONTENT TRUE +#define CC_CHK_AND_COALESCE_SG_LIST FALSE +#define CC_DISABLE_PCI_PARITY_INT TRUE +#define CC_INCLUDE_EEP_CONFIG TRUE +#define CC_INIT_INQ_DISPLAY FALSE +#define CC_INIT_TARGET_TEST_UNIT_READY TRUE +#define CC_INIT_TARGET_START_UNIT TRUE +#define CC_PLEXTOR_VL FALSE +#define CC_TMP_USE_EEP_SDTR FALSE +#define CC_CHK_COND_REDO_SDTR TRUE +#define CC_SET_PCI_LATENCY_TIMER_ZERO TRUE +#define CC_FIX_QUANTUM_XP34301_1071 FALSE +#define CC_DISABLE_ASYN_FIX_WANGTEK_TAPE TRUE #define ASC_CS_TYPE unsigned short - #ifndef asc_ptr_type #define asc_ptr_type #endif -#ifndef CC_SCAM -#define CC_SCAM FALSE -#endif - #ifndef ASC_GET_PTR2FUNC #define ASC_GET_PTR2FUNC( fun ) ( Ptr2Func )( fun ) #endif - #define FLIP_BYTE_NIBBLE( x ) ( ((x<<4)& 0xFF) | (x>>4) ) - #define ASC_IS_ISA (0x0001) #define ASC_IS_ISAPNP (0x0081) #define ASC_IS_EISA (0x0002) #define ASC_IS_PCI (0x0004) +#define ASC_IS_PCI_ULTRA (0x0104) #define ASC_IS_PCMCIA (0x0008) -#define ASC_IS_PNP (0x0010) #define ASC_IS_MCA (0x0020) #define ASC_IS_VL (0x0040) - #define ASC_ISA_PNP_PORT_ADDR (0x279) #define ASC_ISA_PNP_PORT_WRITE (ASC_ISA_PNP_PORT_ADDR+0x800) - #define ASC_IS_WIDESCSI_16 (0x0100) #define ASC_IS_WIDESCSI_32 (0x0200) - #define ASC_IS_BIG_ENDIAN (0x8000) - #define ASC_CHIP_MIN_VER_VL (0x01) #define ASC_CHIP_MAX_VER_VL (0x07) - #define ASC_CHIP_MIN_VER_PCI (0x09) #define ASC_CHIP_MAX_VER_PCI (0x0F) #define ASC_CHIP_VER_PCI_BIT (0x08) - #define ASC_CHIP_MIN_VER_ISA (0x11) #define ASC_CHIP_MIN_VER_ISA_PNP (0x21) #define ASC_CHIP_MAX_VER_ISA (0x27) #define ASC_CHIP_VER_ISA_BIT (0x30) #define ASC_CHIP_VER_ISAPNP_BIT (0x20) - #define ASC_CHIP_VER_ASYN_BUG (0x21) - +#define ASC_CHIP_VER_1ST_PCI_ULTRA (0x0A) #define ASC_CHIP_MIN_VER_EISA (0x41) #define ASC_CHIP_MAX_VER_EISA (0x47) #define ASC_CHIP_VER_EISA_BIT (0x40) - +#define ASC_CHIP_LATEST_VER_EISA ( ( ASC_CHIP_MIN_VER_EISA - 1 ) + 3 ) #define ASC_MAX_VL_DMA_ADDR (0x07FFFFFFL) #define ASC_MAX_VL_DMA_COUNT (0x07FFFFFFL) - #define ASC_MAX_PCI_DMA_ADDR (0xFFFFFFFFL) #define ASC_MAX_PCI_DMA_COUNT (0xFFFFFFFFL) - #define ASC_MAX_ISA_DMA_ADDR (0x00FFFFFFL) #define ASC_MAX_ISA_DMA_COUNT (0x00FFFFFFL) - #define ASC_MAX_EISA_DMA_ADDR (0x07FFFFFFL) #define ASC_MAX_EISA_DMA_COUNT (0x07FFFFFFL) - #if !CC_STRUCT_ALIGNED - #define DvcGetQinfo( iop_base, s_addr, outbuf, words) \ - AscMemWordCopyFromLram( iop_base, s_addr, outbuf, words) - +AscMemWordCopyFromLram(iop_base, s_addr, outbuf, words) #define DvcPutScsiQ( iop_base, s_addr, outbuf, words) \ - AscMemWordCopyToLram( iop_base, s_addr, outbuf, words) - +AscMemWordCopyToLram(iop_base, s_addr, outbuf, words) +#endif +#ifdef ASC_CHIP_VERSION +#endif +#if CC_MEMORY_MAPPED_IO +#define inp( port ) *( (uchar *)(port) ) +#define outp( port, data ) *( (uchar *)(port) ) = ( uchar )( data ) +#if CC_LITTLE_ENDIAN_HOST +#define inpw( port ) *( (ushort *)(port) ) +#define outpw( port, data ) *( (ushort *)(port) ) = ( ushort )( data ) +#else +#define inpw( port ) EndianSwap16Bit( (*((ushort *)(port))) ) +#define outpw( port, data ) *( (ushort *)(port) ) = EndianSwap16Bit( (ushort)(data) ) +#define inpw_noswap( port ) *( (ushort *)(port) ) +#define outpw_noswap( port, data ) *( (ushort *)(port) ) = ( ushort )( data ) +#endif +#endif +#ifndef inpw_noswap +#define inpw_noswap( port ) inpw( port ) +#endif +#ifndef outpw_noswap +#define outpw_noswap( port, data ) outpw( port, data ) #endif - #define ASC_SCSI_ID_BITS 3 #define ASC_SCSI_TIX_TYPE uchar #define ASC_ALL_DEVICE_BIT_SET 0xFF - #ifdef ASC_WIDESCSI_16 - #undef ASC_SCSI_ID_BITS #define ASC_SCSI_ID_BITS 4 #define ASC_ALL_DEVICE_BIT_SET 0xFFFF - #endif - #ifdef ASC_WIDESCSI_32 - #undef ASC_SCSI_ID_BITS #define ASC_SCSI_ID_BITS 5 #define ASC_ALL_DEVICE_BIT_SET 0xFFFFFFFFL - #endif - #if ASC_SCSI_ID_BITS == 3 - #define ASC_SCSI_BIT_ID_TYPE uchar #define ASC_MAX_TID 7 #define ASC_MAX_LUN 7 #define ASC_SCSI_WIDTH_BIT_SET 0xFF - #elif ASC_SCSI_ID_BITS == 4 - #define ASC_SCSI_BIT_ID_TYPE ushort #define ASC_MAX_TID 15 #define ASC_MAX_LUN 7 #define ASC_SCSI_WIDTH_BIT_SET 0xFFFF - #elif ASC_SCSI_ID_BITS == 5 - #define ASC_SCSI_BIT_ID_TYPE ulong #define ASC_MAX_TID 31 #define ASC_MAX_LUN 7 #define ASC_SCSI_WIDTH_BIT_SET 0xFFFFFFFF - #else - #error ASC_SCSI_ID_BITS definition is wrong - #endif - #define ASC_MAX_SENSE_LEN 32 #define ASC_MIN_SENSE_LEN 14 - #define ASC_MAX_CDB_LEN 12 - #define SCSICMD_TestUnitReady 0x00 #define SCSICMD_Rewind 0x01 #define SCSICMD_Rezero 0x01 @@ -787,7 +748,6 @@ #define SCSICMD_Verify6 0x13 #define SCSICMD_ModeSelect6 0x15 #define SCSICMD_ModeSense6 0x1A - #define SCSICMD_StartStopUnit 0x1B #define SCSICMD_LoadUnloadTape 0x1B #define SCSICMD_ReadCapacity 0x25 @@ -797,15 +757,18 @@ #define SCSICMD_Erase10 0x2C #define SCSICMD_WriteAndVerify10 0x2E #define SCSICMD_Verify10 0x2F - +#define SCSICMD_WriteBuffer 0x3B +#define SCSICMD_ReadBuffer 0x3C +#define SCSICMD_ReadLong 0x3E +#define SCSICMD_WriteLong 0x3F +#define SCSICMD_ReadTOC 0x43 +#define SCSICMD_ReadHeader 0x44 #define SCSICMD_ModeSelect10 0x55 #define SCSICMD_ModeSense10 0x5A - #define SCSI_TYPE_DASD 0x00 #define SCSI_TYPE_SASD 0x01 #define SCSI_TYPE_PRN 0x02 #define SCSI_TYPE_PROC 0x03 - #define SCSI_TYPE_WORM 0x04 #define SCSI_TYPE_CDROM 0x05 #define SCSI_TYPE_SCANNER 0x06 @@ -814,15 +777,10 @@ #define SCSI_TYPE_COMM 0x09 #define SCSI_TYPE_UNKNOWN 0x1F #define SCSI_TYPE_NO_DVC 0xFF - #define ASC_SCSIDIR_NOCHK 0x00 - #define ASC_SCSIDIR_T2H 0x08 - #define ASC_SCSIDIR_H2T 0x10 - #define ASC_SCSIDIR_NODATA 0x18 - #define SCSI_SENKEY_NO_SENSE 0x00 #define SCSI_SENKEY_UNDEFINED 0x01 #define SCSI_SENKEY_NOT_READY 0x02 @@ -839,31 +797,23 @@ #define SCSI_SENKEY_VOL_OVERFLOW 0x0D #define SCSI_SENKEY_MISCOMP 0x0E #define SCSI_SENKEY_RESERVED 0x0F - #define ASC_SRB_HOST( x ) ( ( uchar )( ( uchar )( x ) >> 4 ) ) #define ASC_SRB_TID( x ) ( ( uchar )( ( uchar )( x ) & ( uchar )0x0F ) ) - #define ASC_SRB_LUN( x ) ( ( uchar )( ( uint )( x ) >> 13 ) ) - #define PUT_CDB1( x ) ( ( uchar )( ( uint )( x ) >> 8 ) ) - #define SS_GOOD 0x00 #define SS_CHK_CONDITION 0x02 #define SS_CONDITION_MET 0x04 #define SS_TARGET_BUSY 0x08 #define SS_INTERMID 0x10 #define SS_INTERMID_COND_MET 0x14 - #define SS_RSERV_CONFLICT 0x18 #define SS_CMD_TERMINATED 0x22 - #define SS_QUEUE_FULL 0x28 - #define MS_CMD_DONE 0x00 #define MS_EXTEND 0x01 #define MS_SDTR_LEN 0x03 #define MS_SDTR_CODE 0x01 - #define M1_SAVE_DATA_PTR 0x02 #define M1_RESTORE_PTRS 0x03 #define M1_DISCONNECT 0x04 @@ -880,36 +830,69 @@ #define M1_INIT_RECOVERY 0x0F #define M1_RELEASE_RECOVERY 0x10 #define M1_KILL_IO_PROC 0x11 - #define M2_QTAG_MSG_SIMPLE 0x20 #define M2_QTAG_MSG_HEAD 0x21 #define M2_QTAG_MSG_ORDERED 0x22 #define M2_IGNORE_WIDE_RESIDUE 0x23 - +#if CC_LITTLE_ENDIAN_HOST typedef struct { uchar peri_dvc_type:5; uchar peri_qualifier:3; } ASC_SCSI_INQ0; +#else +typedef struct { + uchar peri_qualifier:3; + uchar peri_dvc_type:5; +} ASC_SCSI_INQ0; + +#endif +#if CC_LITTLE_ENDIAN_HOST typedef struct { uchar dvc_type_modifier:7; uchar rmb:1; } ASC_SCSI_INQ1; +#else +typedef struct { + uchar rmb:1; + uchar dvc_type_modifier:7; +} ASC_SCSI_INQ1; + +#endif +#if CC_LITTLE_ENDIAN_HOST typedef struct { uchar ansi_apr_ver:3; uchar ecma_ver:3; uchar iso_ver:2; } ASC_SCSI_INQ2; +#else typedef struct { - uchar rsp_data_fmt:4; + uchar iso_ver:2; + uchar ecma_ver:3; + uchar ansi_apr_ver:3; +} ASC_SCSI_INQ2; +#endif +#if CC_LITTLE_ENDIAN_HOST +typedef struct { + uchar rsp_data_fmt:4; uchar res:2; uchar TemIOP:1; uchar aenc:1; } ASC_SCSI_INQ3; +#else +typedef struct { + uchar aenc:1; + uchar TemIOP:1; + uchar res:2; + uchar rsp_data_fmt:4; +} ASC_SCSI_INQ3; + +#endif +#if CC_LITTLE_ENDIAN_HOST typedef struct { uchar StfRe:1; uchar CmdQue:1; @@ -921,6 +904,19 @@ uchar RelAdr:1; } ASC_SCSI_INQ7; +#else +typedef struct { + uchar RelAdr:1; + uchar WBus32:1; + uchar WBus16:1; + uchar Sync:1; + uchar Linked:1; + uchar Reserved:1; + uchar CmdQue:1; + uchar StfRe:1; +} ASC_SCSI_INQ7; + +#endif typedef struct { ASC_SCSI_INQ0 byte0; ASC_SCSI_INQ1 byte1; @@ -935,6 +931,7 @@ uchar product_rev_level[4]; } ASC_SCSI_INQUIRY; +#if CC_LITTLE_ENDIAN_HOST typedef struct asc_req_sense { uchar err_code:7; uchar info_valid:1; @@ -949,7 +946,6 @@ uchar cmd_sp_info[4]; uchar asc; uchar ascq; - uchar fruc; uchar sks_byte0:7; uchar sks_valid:1; @@ -959,32 +955,50 @@ uchar info2[4]; } ASC_REQ_SENSE; -#define ASC_SG_LIST_PER_Q 7 +#else +typedef struct asc_req_sense { + uchar info_valid:1; + uchar err_code:7; + uchar segment_no; + uchar file_mark:1; + uchar sense_EOM:1; + uchar sense_ILI:1; + uchar reserved_bit:1; + uchar sense_key:4; + uchar info1[4]; + uchar add_sense_len; + uchar cmd_sp_info[4]; + uchar asc; + uchar ascq; + uchar fruc; + uchar sks_valid:1; + uchar sks_byte0:7; + uchar sks_bytes[2]; + uchar notused[2]; + uchar ex_sense_code; + uchar info2[4]; +} ASC_REQ_SENSE; +#endif +#define ASC_SG_LIST_PER_Q 7 #define QS_FREE 0x00 #define QS_READY 0x01 #define QS_DISC1 0x02 #define QS_DISC2 0x04 #define QS_BUSY 0x08 - #define QS_ABORTED 0x40 #define QS_DONE 0x80 - #define QC_NO_CALLBACK 0x01 - #define QC_SG_SWAP_QUEUE 0x02 #define QC_SG_HEAD 0x04 #define QC_DATA_IN 0x08 #define QC_DATA_OUT 0x10 - #define QC_URGENT 0x20 #define QC_MSG_OUT 0x40 #define QC_REQ_SENSE 0x80 - #define QCSG_SG_XFER_LIST 0x02 #define QCSG_SG_XFER_MORE 0x04 #define QCSG_SG_XFER_END 0x08 - #define QD_IN_PROGRESS 0x00 #define QD_NO_ERROR 0x01 #define QD_ABORTED_BY_HOST 0x02 @@ -993,59 +1007,48 @@ #define QD_INVALID_HOST_NUM 0x81 #define QD_INVALID_DEVICE 0x82 #define QD_ERR_INTERNAL 0xFF - #define QHSTA_NO_ERROR 0x00 #define QHSTA_M_SEL_TIMEOUT 0x11 #define QHSTA_M_DATA_OVER_RUN 0x12 #define QHSTA_M_DATA_UNDER_RUN 0x12 #define QHSTA_M_UNEXPECTED_BUS_FREE 0x13 #define QHSTA_M_BAD_BUS_PHASE_SEQ 0x14 - #define QHSTA_D_QDONE_SG_LIST_CORRUPTED 0x21 #define QHSTA_D_ASC_DVC_ERROR_CODE_SET 0x22 #define QHSTA_D_HOST_ABORT_FAILED 0x23 #define QHSTA_D_EXE_SCSI_Q_FAILED 0x24 #define QHSTA_D_EXE_SCSI_Q_BUSY_TIMEOUT 0x25 - #define QHSTA_D_ASPI_NO_BUF_POOL 0x26 - #define QHSTA_M_WTM_TIMEOUT 0x41 #define QHSTA_M_BAD_CMPL_STATUS_IN 0x42 #define QHSTA_M_NO_AUTO_REQ_SENSE 0x43 #define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44 #define QHSTA_M_TARGET_STATUS_BUSY 0x45 #define QHSTA_M_BAD_TAG_CODE 0x46 - #define QHSTA_M_BAD_QUEUE_FULL_OR_BUSY 0x47 - +#define QHSTA_M_HUNG_REQ_SCSI_BUS_RESET 0x48 #define QHSTA_D_LRAM_CMP_ERROR 0x81 #define QHSTA_M_MICRO_CODE_ERROR_HALT 0xA1 - #define ASC_FLAG_SCSIQ_REQ 0x01 #define ASC_FLAG_BIOS_SCSIQ_REQ 0x02 #define ASC_FLAG_BIOS_ASYNC_IO 0x04 #define ASC_FLAG_SRB_LINEAR_ADDR 0x08 - #define ASC_FLAG_WIN16 0x10 #define ASC_FLAG_WIN32 0x20 - +#define ASC_FLAG_ISA_OVER_16MB 0x40 #define ASC_FLAG_DOS_VM_CALLBACK 0x80 - -#define ASC_TAG_FLAG_ADD_ONE_BYTE 0x10 -#define ASC_TAG_FLAG_ISAPNP_ADD_BYTES 0x40 - +#define ASC_TAG_FLAG_EXTRA_BYTES 0x10 +#define ASC_TAG_FLAG_DISABLE_DISCONNECT 0x04 +#define ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX 0x08 +#define ASC_TAG_FLAG_DISABLE_CHK_COND_INT_HOST 0x40 #define ASC_SCSIQ_CPY_BEG 4 #define ASC_SCSIQ_SGHD_CPY_BEG 2 - #define ASC_SCSIQ_B_FWD 0 #define ASC_SCSIQ_B_BWD 1 - #define ASC_SCSIQ_B_STATUS 2 #define ASC_SCSIQ_B_QNO 3 - #define ASC_SCSIQ_B_CNTL 4 #define ASC_SCSIQ_B_SG_QUEUE_CNT 5 - #define ASC_SCSIQ_D_DATA_ADDR 8 #define ASC_SCSIQ_D_DATA_CNT 12 #define ASC_SCSIQ_B_SENSE_LEN 20 @@ -1066,37 +1069,27 @@ #define ASC_SCSIQ_W_REQ_COUNT 52 #define ASC_SCSIQ_B_LIST_CNT 6 #define ASC_SCSIQ_B_CUR_LIST_CNT 7 - #define ASC_SGQ_B_SG_CNTL 4 #define ASC_SGQ_B_SG_HEAD_QP 5 #define ASC_SGQ_B_SG_LIST_CNT 6 #define ASC_SGQ_B_SG_CUR_LIST_CNT 7 #define ASC_SGQ_LIST_BEG 8 - -#define ASC_DEF_SCSI1_QNG 2 -#define ASC_MAX_SCSI1_QNG 2 +#define ASC_DEF_SCSI1_QNG 4 +#define ASC_MAX_SCSI1_QNG 4 #define ASC_DEF_SCSI2_QNG 16 #define ASC_MAX_SCSI2_QNG 32 - #define ASC_TAG_CODE_MASK 0x23 - #define ASC_STOP_REQ_RISC_STOP 0x01 - #define ASC_STOP_ACK_RISC_STOP 0x03 - #define ASC_STOP_CLEAN_UP_BUSY_Q 0x10 #define ASC_STOP_CLEAN_UP_DISC_Q 0x20 #define ASC_STOP_HOST_REQ_RISC_HALT 0x40 -#define ASC_STOP_SEND_INT_TO_HOST 0x80 - #define ASC_TIDLUN_TO_IX( tid, lun ) ( ASC_SCSI_TIX_TYPE )( (tid) + ((lun)<> ASC_SCSI_ID_BITS ) & ASC_MAX_LUN ) - +#define ASC_TIX_TO_TID( tix ) ( (tix) & ASC_MAX_TID ) +#define ASC_TID_TO_TIX( tid ) ( (tid) & ASC_MAX_TID ) +#define ASC_TIX_TO_LUN( tix ) ( ( (tix) >> ASC_SCSI_ID_BITS ) & ASC_MAX_LUN ) #define ASC_QNO_TO_QADDR( q_no ) ( (ASC_QADR_BEG)+( ( int )(q_no) << 6 ) ) typedef struct asc_scisq_1 { @@ -1104,25 +1097,21 @@ uchar q_no; uchar cntl; uchar sg_queue_cnt; - uchar target_id; uchar target_lun; - ulong data_addr; ulong data_cnt; ulong sense_addr; uchar sense_len; - uchar user_def; + uchar extra_bytes; } ASC_SCSIQ_1; typedef struct asc_scisq_2 { ulong srb_ptr; uchar target_ix; - uchar flag; uchar cdb_len; uchar tag_code; - ushort vm_id; } ASC_SCSIQ_2; @@ -1138,7 +1127,7 @@ uchar y_first_sg_list_qp; uchar y_working_sg_qp; uchar y_working_sg_ix; - uchar y_cntl; + uchar y_res; ushort x_req_count; ushort x_reconnect_rtn; ulong x_saved_data_addr; @@ -1152,7 +1141,7 @@ uchar q_no; uchar cntl; uchar sense_len; - uchar user_def; + uchar extra_bytes; uchar res; ulong remain_bytes; } ASC_QDONE_INFO; @@ -1163,24 +1152,20 @@ } ASC_SG_LIST; typedef struct asc_sg_head { - uchar entry_cnt; - - uchar queue_cnt; - - uchar entry_to_copy; - uchar res; + ushort entry_cnt; + ushort queue_cnt; + ushort entry_to_copy; + ushort res; ASC_SG_LIST sg_list[ASC_MAX_SG_LIST]; } ASC_SG_HEAD; #define ASC_MIN_SG_LIST 2 typedef struct asc_min_sg_head { - uchar entry_cnt; - - uchar queue_cnt; - - uchar entry_to_copy; - uchar res; + ushort entry_cnt; + ushort queue_cnt; + ushort entry_to_copy; + ushort res; ASC_SG_LIST sg_list[ASC_MIN_SG_LIST]; } ASC_MIN_SG_HEAD; @@ -1198,20 +1183,19 @@ uchar q_required; uchar res; } ASC_EXT_SCSI_Q; - #endif typedef struct asc_scsi_q { ASC_SCSIQ_1 q1; ASC_SCSIQ_2 q2; uchar dosfar *cdbptr; - ASC_SG_HEAD dosfar *sg_head; - #if CC_LINK_BUSY_Q ASC_EXT_SCSI_Q ext; #endif - +#if CC_ASC_SCSI_Q_USRDEF + ASC_SCSI_Q_USR usr; +#endif } ASC_SCSI_Q; typedef struct asc_scsi_req_q { @@ -1219,18 +1203,29 @@ ASC_SCSIQ_2 r2; uchar dosfar *cdbptr; ASC_SG_HEAD dosfar *sg_head; - #if CC_LINK_BUSY_Q ASC_EXT_SCSI_Q ext; #endif - uchar dosfar *sense_ptr; - ASC_SCSIQ_3 r3; uchar cdb[ASC_MAX_CDB_LEN]; uchar sense[ASC_MIN_SENSE_LEN]; +#if CC_ASC_SCSI_REQ_Q_USRDEF + ASC_SCSI_REQ_Q_USR usr; +#endif } ASC_SCSI_REQ_Q; +typedef struct asc_scsi_bios_req_q { + ASC_SCSIQ_1 r1; + ASC_SCSIQ_2 r2; + uchar dosfar *cdbptr; + ASC_SG_HEAD dosfar *sg_head; + uchar dosfar *sense_ptr; + ASC_SCSIQ_3 r3; + uchar cdb[ASC_MAX_CDB_LEN]; + uchar sense[ASC_MIN_SENSE_LEN]; +} ASC_SCSI_BIOS_REQ_Q; + typedef struct asc_risc_q { uchar fwd; uchar bwd; @@ -1241,14 +1236,12 @@ } ASC_RISC_Q; typedef struct asc_sg_list_q { - uchar seq_no; uchar q_no; uchar cntl; uchar sg_head_qp; uchar sg_list_cnt; uchar sg_cur_list_cnt; - } ASC_SG_LIST_Q; typedef struct asc_risc_sg_list_q { @@ -1260,7 +1253,6 @@ #define ASC_EXE_SCSI_IO_MAX_IDLE_LOOP 0x1000000UL #define ASC_EXE_SCSI_IO_MAX_WAIT_LOOP 1024 - #define ASCQ_ERR_NO_ERROR 0 #define ASCQ_ERR_IO_NOT_FOUND 1 #define ASCQ_ERR_LOCAL_MEM 2 @@ -1298,24 +1290,20 @@ #define ASCQ_ERR_SEND_SCSI_Q 0x22 #define ASCQ_ERR_HOST_REQ_RISC_HALT 0x23 #define ASCQ_ERR_RESET_SDTR 0x24 - #define ASC_WARN_NO_ERROR 0x0000 #define ASC_WARN_IO_PORT_ROTATE 0x0001 #define ASC_WARN_EEPROM_CHKSUM 0x0002 #define ASC_WARN_IRQ_MODIFIED 0x0004 #define ASC_WARN_AUTO_CONFIG 0x0008 #define ASC_WARN_CMD_QNG_CONFLICT 0x0010 - #define ASC_WARN_EEPROM_RECOVER 0x0020 #define ASC_WARN_CFG_MSW_RECOVER 0x0040 - +#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080 #define ASC_IERR_WRITE_EEPROM 0x0001 #define ASC_IERR_MCODE_CHKSUM 0x0002 #define ASC_IERR_SET_PC_ADDR 0x0004 #define ASC_IERR_START_STOP_CHIP 0x0008 - #define ASC_IERR_IRQ_NO 0x0010 - #define ASC_IERR_SET_IRQ_NO 0x0020 #define ASC_IERR_CHIP_VERSION 0x0040 #define ASC_IERR_SET_SCSI_ID 0x0080 @@ -1325,36 +1313,82 @@ #define ASC_IERR_SCAM 0x0800 #define ASC_IERR_SET_SDTR 0x1000 #define ASC_IERR_RW_LRAM 0x8000 - #define ASC_DEF_IRQ_NO 10 #define ASC_MAX_IRQ_NO 15 #define ASC_MIN_IRQ_NO 10 - #define ASC_MIN_REMAIN_Q (0x02) -#define ASC_DEF_MAX_TOTAL_QNG (0x40) - +#define ASC_DEF_MAX_TOTAL_QNG (0xF0) #define ASC_MIN_TAG_Q_PER_DVC (0x04) #define ASC_DEF_TAG_Q_PER_DVC (0x04) - #define ASC_MIN_FREE_Q ASC_MIN_REMAIN_Q - #define ASC_MIN_TOTAL_QNG (( ASC_MAX_SG_QUEUE )+( ASC_MIN_FREE_Q )) - #define ASC_MAX_TOTAL_QNG 240 -#define ASC_MAX_PCI_INRAM_TOTAL_QNG 20 - +#define ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG 16 +#define ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG 8 +#define ASC_MAX_PCI_INRAM_TOTAL_QNG 20 #define ASC_MAX_INRAM_TAG_QNG 16 +#define ASC_IOADR_TABLE_MAX_IX 11 +#define ASC_IOADR_GAP 0x10 +#define ASC_SEARCH_IOP_GAP 0x10 +#define ASC_MIN_IOP_ADDR ( PortAddr )0x0100 +#define ASC_MAX_IOP_ADDR ( PortAddr )0x3F0 +#define ASC_IOADR_1 ( PortAddr )0x0110 +#define ASC_IOADR_2 ( PortAddr )0x0130 +#define ASC_IOADR_3 ( PortAddr )0x0150 +#define ASC_IOADR_4 ( PortAddr )0x0190 +#define ASC_IOADR_5 ( PortAddr )0x0210 +#define ASC_IOADR_6 ( PortAddr )0x0230 +#define ASC_IOADR_7 ( PortAddr )0x0250 +#define ASC_IOADR_8 ( PortAddr )0x0330 +#define ASC_IOADR_DEF ASC_IOADR_8 +#define ASC_LIB_SCSIQ_WK_SP 256 +#define ASC_MAX_SYN_XFER_NO 16 +#define ASC_SYN_XFER_NO 8 +#define ASC_SYN_MAX_OFFSET 0x0F +#define ASC_DEF_SDTR_OFFSET 0x0F +#define ASC_DEF_SDTR_INDEX 0x00 +#define SYN_XFER_NS_0 25 +#define SYN_XFER_NS_1 30 +#define SYN_XFER_NS_2 35 +#define SYN_XFER_NS_3 40 +#define SYN_XFER_NS_4 50 +#define SYN_XFER_NS_5 60 +#define SYN_XFER_NS_6 70 +#define SYN_XFER_NS_7 85 +#define SYN_ULTRA_XFER_NS_0 12 +#define SYN_ULTRA_XFER_NS_1 19 +#define SYN_ULTRA_XFER_NS_2 25 +#define SYN_ULTRA_XFER_NS_3 32 +#define SYN_ULTRA_XFER_NS_4 38 +#define SYN_ULTRA_XFER_NS_5 44 +#define SYN_ULTRA_XFER_NS_6 50 +#define SYN_ULTRA_XFER_NS_7 57 +#define SYN_ULTRA_XFER_NS_8 63 +#define SYN_ULTRA_XFER_NS_9 69 +#define SYN_ULTRA_XFER_NS_10 75 +#define SYN_ULTRA_XFER_NS_11 82 +#define SYN_ULTRA_XFER_NS_12 88 +#define SYN_ULTRA_XFER_NS_13 94 +#define SYN_ULTRA_XFER_NS_14 100 +#define SYN_ULTRA_XFER_NS_15 107 +#define SYN_XMSG_WLEN 3 + +typedef struct sdtr_xmsg { + uchar msg_type; + uchar msg_len; + uchar msg_req; + uchar xfer_period; + uchar req_ack_offset; + uchar res; +} SDTR_XMSG; typedef struct asc_dvc_cfg { ASC_SCSI_BIT_ID_TYPE can_tagged_qng; - ASC_SCSI_BIT_ID_TYPE cmd_qng_enabled; ASC_SCSI_BIT_ID_TYPE disc_enable; uchar res; uchar chip_scsi_id:4; - uchar isa_dma_speed:4; - uchar isa_dma_channel; uchar chip_version; ushort pci_device_id; @@ -1362,16 +1396,15 @@ ushort lib_version; ushort mcode_date; ushort mcode_version; - uchar sdtr_data[ASC_MAX_TID + 1]; uchar max_tag_qng[ASC_MAX_TID + 1]; uchar dosfar *overrun_buf; - + uchar sdtr_period_offset[ASC_MAX_TID + 1]; + ushort pci_slot_info; } ASC_DVC_CFG; #define ASC_DEF_DVC_CNTL 0xFFFF #define ASC_DEF_CHIP_SCSI_ID 7 #define ASC_DEF_ISA_DMA_SPEED 4 - #define ASC_INIT_STATE_NULL 0x0000 #define ASC_INIT_STATE_BEG_GET_CFG 0x0001 #define ASC_INIT_STATE_END_GET_CFG 0x0002 @@ -1382,15 +1415,14 @@ #define ASC_INIT_STATE_BEG_INQUIRY 0x0040 #define ASC_INIT_STATE_END_INQUIRY 0x0080 #define ASC_INIT_RESET_SCSI_DONE 0x0100 - +#define ASC_INIT_STATE_WITHOUT_EEP 0x8000 #define ASC_PCI_DEVICE_ID_REV_A 0x1100 #define ASC_PCI_DEVICE_ID_REV_B 0x1200 - -#define ASC_BUG_FIX_ADD_ONE_BYTE 0x0001 - +#define ASC_BUG_FIX_IF_NOT_DWB 0x0001 +#define ASC_BUG_FIX_ASYN_USE_SYN 0x0002 #define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41 - #define ASC_MIN_TAGGED_CMD 7 +#define ASC_MAX_SCSI_RESET_WAIT 30 typedef struct asc_dvc_var { PortAddr iop_base; @@ -1400,49 +1432,41 @@ ushort bus_type; Ptr2Func isr_callback; Ptr2Func exe_callback; - ASC_SCSI_BIT_ID_TYPE init_sdtr; - ASC_SCSI_BIT_ID_TYPE sdtr_done; - ASC_SCSI_BIT_ID_TYPE use_tagged_qng; - ASC_SCSI_BIT_ID_TYPE unit_not_ready; - ASC_SCSI_BIT_ID_TYPE queue_full_or_busy; - ASC_SCSI_BIT_ID_TYPE start_motor; uchar scsi_reset_wait; uchar chip_no; - char is_in_int; uchar max_total_qng; - uchar cur_total_qng; - uchar in_critical_cnt; - uchar irq_no; uchar last_q_shortage; - ushort init_state; uchar cur_dvc_qng[ASC_MAX_TID + 1]; uchar max_dvc_qng[ASC_MAX_TID + 1]; - ASC_SCSI_Q dosfar *scsiq_busy_head[ASC_MAX_TID + 1]; ASC_SCSI_Q dosfar *scsiq_busy_tail[ASC_MAX_TID + 1]; - - ulong int_count; - ulong req_count; - ulong busy_count; - + uchar sdtr_period_tbl[ASC_MAX_SYN_XFER_NO]; ASC_DVC_CFG dosfar *cfg; Ptr2Func saved_ptr2func; - ulong reserved2; - ulong reserved3; + ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer_always; + char redo_scam; + ushort res2; + uchar dos_int13_table[ASC_MAX_TID + 1]; ulong max_dma_count; ASC_SCSI_BIT_ID_TYPE no_scam; ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer; + uchar max_sdtr_index; + uchar res4; + ulong drv_ptr; + ulong res6; + ulong res7; + ulong res8; } ASC_DVC_VAR; typedef int (dosfar * ASC_ISR_CALLBACK) (ASC_DVC_VAR asc_ptr_type *, ASC_QDONE_INFO dosfar *); @@ -1461,115 +1485,50 @@ ASC_CAP_INFO cap_info[ASC_MAX_TID + 1][ASC_MAX_LUN + 1]; } ASC_CAP_INFO_ARRAY; -#define ASC_IOADR_TABLE_MAX_IX 11 -#define ASC_IOADR_GAP 0x10 -#define ASC_SEARCH_IOP_GAP 0x10 -#define ASC_MIN_IOP_ADDR ( PortAddr )0x0100 -#define ASC_MAX_IOP_ADDR ( PortAddr )0x3F0 - -#define ASC_IOADR_1 ( PortAddr )0x0110 -#define ASC_IOADR_2 ( PortAddr )0x0130 -#define ASC_IOADR_3 ( PortAddr )0x0150 -#define ASC_IOADR_4 ( PortAddr )0x0190 -#define ASC_IOADR_5 ( PortAddr )0x0210 -#define ASC_IOADR_6 ( PortAddr )0x0230 -#define ASC_IOADR_7 ( PortAddr )0x0250 -#define ASC_IOADR_8 ( PortAddr )0x0330 -#define ASC_IOADR_DEF ASC_IOADR_8 - -#define ASC_SYN_XFER_NO 8 -#define ASC_MAX_SDTR_PERIOD_INDEX 7 -#define ASC_SYN_MAX_OFFSET 0x0F -#define ASC_DEF_SDTR_OFFSET 0x0F -#define ASC_DEF_SDTR_INDEX 0x00 - -#define SYN_XFER_NS_0 25 -#define SYN_XFER_NS_1 30 -#define SYN_XFER_NS_2 35 -#define SYN_XFER_NS_3 40 -#define SYN_XFER_NS_4 50 -#define SYN_XFER_NS_5 60 -#define SYN_XFER_NS_6 70 -#define SYN_XFER_NS_7 85 - -#define ASC_SDTR_PERIOD_IX_MIN 7 - -#define SYN_XMSG_WLEN 3 - -typedef struct sdtr_xmsg { - uchar msg_type; - uchar msg_len; - uchar msg_req; - uchar xfer_period; - uchar req_ack_offset; - uchar res; -} SDTR_XMSG; - #define ASC_MCNTL_NO_SEL_TIMEOUT ( ushort )0x0001 #define ASC_MCNTL_NULL_TARGET ( ushort )0x0002 - #define ASC_CNTL_INITIATOR ( ushort )0x0001 #define ASC_CNTL_BIOS_GT_1GB ( ushort )0x0002 #define ASC_CNTL_BIOS_GT_2_DISK ( ushort )0x0004 #define ASC_CNTL_BIOS_REMOVABLE ( ushort )0x0008 #define ASC_CNTL_NO_SCAM ( ushort )0x0010 -#define ASC_CNTL_NO_PCI_FIX_ASYN_XFER ( ushort )0x0020 - #define ASC_CNTL_INT_MULTI_Q ( ushort )0x0080 - #define ASC_CNTL_NO_LUN_SUPPORT ( ushort )0x0040 - #define ASC_CNTL_NO_VERIFY_COPY ( ushort )0x0100 #define ASC_CNTL_RESET_SCSI ( ushort )0x0200 #define ASC_CNTL_INIT_INQUIRY ( ushort )0x0400 #define ASC_CNTL_INIT_VERBOSE ( ushort )0x0800 - #define ASC_CNTL_SCSI_PARITY ( ushort )0x1000 #define ASC_CNTL_BURST_MODE ( ushort )0x2000 - #define ASC_CNTL_USE_8_IOP_BASE ( ushort )0x4000 - #define ASC_EEP_DVC_CFG_BEG_VL 2 #define ASC_EEP_MAX_DVC_ADDR_VL 15 - #define ASC_EEP_DVC_CFG_BEG 32 #define ASC_EEP_MAX_DVC_ADDR 45 - #define ASC_EEP_DEFINED_WORDS 10 #define ASC_EEP_MAX_ADDR 63 #define ASC_EEP_RES_WORDS 0 #define ASC_EEP_MAX_RETRY 20 #define ASC_MAX_INIT_BUSY_RETRY 8 - #define ASC_EEP_ISA_PNP_WSIZE 16 typedef struct asceep_config { ushort cfg_lsw; ushort cfg_msw; - uchar init_sdtr; uchar disc_enable; - uchar use_cmd_qng; - uchar start_motor; uchar max_total_qng; uchar max_tag_qng; uchar bios_scan; - uchar power_up_wait; - uchar no_scam; uchar chip_scsi_id:4; - uchar isa_dma_speed:4; - - uchar sdtr_data[ASC_MAX_TID + 1]; - + uchar dos_int13_table[ASC_MAX_TID + 1]; uchar adapter_info[6]; - ushort cntl; - ushort chksum; } ASCEEP_CONFIG; @@ -1577,30 +1536,23 @@ #define ASC_EEP_CMD_WRITE 0x40 #define ASC_EEP_CMD_WRITE_ABLE 0x30 #define ASC_EEP_CMD_WRITE_DISABLE 0x00 - #define ASC_OVERRUN_BSIZE 0x00000048UL - #define ASCV_MSGOUT_BEG 0x0000 #define ASCV_MSGOUT_SDTR_PERIOD (ASCV_MSGOUT_BEG+3) #define ASCV_MSGOUT_SDTR_OFFSET (ASCV_MSGOUT_BEG+4) - #define ASCV_MSGIN_BEG (ASCV_MSGOUT_BEG+8) #define ASCV_MSGIN_SDTR_PERIOD (ASCV_MSGIN_BEG+3) #define ASCV_MSGIN_SDTR_OFFSET (ASCV_MSGIN_BEG+4) - #define ASCV_SDTR_DATA_BEG (ASCV_MSGIN_BEG+8) #define ASCV_SDTR_DONE_BEG (ASCV_SDTR_DATA_BEG+8) #define ASCV_MAX_DVC_QNG_BEG ( ushort )0x0020 - #define ASCV_ASCDVC_ERR_CODE_W ( ushort )0x0030 #define ASCV_MCODE_CHKSUM_W ( ushort )0x0032 #define ASCV_MCODE_SIZE_W ( ushort )0x0034 #define ASCV_STOP_CODE_B ( ushort )0x0036 #define ASCV_DVC_ERR_CODE_B ( ushort )0x0037 - #define ASCV_OVERRUN_PADDR_D ( ushort )0x0038 #define ASCV_OVERRUN_BSIZE_D ( ushort )0x003C - #define ASCV_HALTCODE_W ( ushort )0x0040 #define ASCV_CHKSUM_W ( ushort )0x0042 #define ASCV_MC_DATE_W ( ushort )0x0044 @@ -1609,57 +1561,47 @@ #define ASCV_DONENEXT_B ( ushort )0x0049 #define ASCV_USE_TAGGED_QNG_B ( ushort )0x004A #define ASCV_SCSIBUSY_B ( ushort )0x004B -#define ASCV_CDBCNT_B ( ushort )0x004C +#define ASCV_Q_DONE_IN_PROGRESS_B ( ushort )0x004C #define ASCV_CURCDB_B ( ushort )0x004D #define ASCV_RCLUN_B ( ushort )0x004E #define ASCV_BUSY_QHEAD_B ( ushort )0x004F #define ASCV_DISC1_QHEAD_B ( ushort )0x0050 - #define ASCV_DISC_ENABLE_B ( ushort )0x0052 #define ASCV_CAN_TAGGED_QNG_B ( ushort )0x0053 #define ASCV_HOSTSCSI_ID_B ( ushort )0x0055 #define ASCV_MCODE_CNTL_B ( ushort )0x0056 #define ASCV_NULL_TARGET_B ( ushort )0x0057 - #define ASCV_FREE_Q_HEAD_W ( ushort )0x0058 #define ASCV_DONE_Q_TAIL_W ( ushort )0x005A #define ASCV_FREE_Q_HEAD_B ( ushort )(ASCV_FREE_Q_HEAD_W+1) #define ASCV_DONE_Q_TAIL_B ( ushort )(ASCV_DONE_Q_TAIL_W+1) - #define ASCV_HOST_FLAG_B ( ushort )0x005D - #define ASCV_TOTAL_READY_Q_B ( ushort )0x0064 #define ASCV_VER_SERIAL_B ( ushort )0x0065 #define ASCV_HALTCODE_SAVED_W ( ushort )0x0066 #define ASCV_WTM_FLAG_B ( ushort )0x0068 #define ASCV_RISC_FLAG_B ( ushort )0x006A #define ASCV_REQ_SG_LIST_QP ( ushort )0x006B - #define ASC_HOST_FLAG_IN_ISR 0x01 #define ASC_HOST_FLAG_ACK_INT 0x02 - #define ASC_RISC_FLAG_GEN_INT 0x01 #define ASC_RISC_FLAG_REQ_SG_LIST 0x02 - #define IOP_CTRL (0x0F) #define IOP_STATUS (0x0E) #define IOP_INT_ACK IOP_STATUS - #define IOP_REG_IFC (0x0D) - -#define IOP_SYN_OFFSET (0x0B) -#define IOP_REG_PC (0x0C) -#define IOP_RAM_ADDR (0x0A) -#define IOP_RAM_DATA (0x08) -#define IOP_EEP_DATA (0x06) -#define IOP_EEP_CMD (0x07) - -#define IOP_VERSION (0x03) -#define IOP_CONFIG_HIGH (0x04) -#define IOP_CONFIG_LOW (0x02) -#define IOP_ASPI_ID_LOW (0x01) -#define IOP_ASPI_ID_HIGH (0x00) - +#define IOP_SYN_OFFSET (0x0B) +#define IOP_EXTRA_CONTROL (0x0D) +#define IOP_REG_PC (0x0C) +#define IOP_RAM_ADDR (0x0A) +#define IOP_RAM_DATA (0x08) +#define IOP_EEP_DATA (0x06) +#define IOP_EEP_CMD (0x07) +#define IOP_VERSION (0x03) +#define IOP_CONFIG_HIGH (0x04) +#define IOP_CONFIG_LOW (0x02) +#define IOP_SIG_BYTE (0x01) +#define IOP_SIG_WORD (0x00) #define IOP_REG_DC1 (0x0E) #define IOP_REG_DC0 (0x0C) #define IOP_REG_SB (0x0B) @@ -1675,85 +1617,30 @@ #define IOP_REG_IH (0x02) #define IOP_REG_IX (0x01) #define IOP_REG_AX (0x00) - #define IFC_REG_LOCK (0x00) #define IFC_REG_UNLOCK (0x09) - #define IFC_WR_EN_FILTER (0x10) #define IFC_RD_NO_EEPROM (0x10) #define IFC_SLEW_RATE (0x20) #define IFC_ACT_NEG (0x40) #define IFC_INP_FILTER (0x80) - #define IFC_INIT_DEFAULT ( IFC_ACT_NEG | IFC_REG_UNLOCK ) - -#define SC_SEL (0x80) -#define SC_BSY (0x40) -#define SC_ACK (0x20) -#define SC_REQ (0x10) -#define SC_ATN (0x08) -#define SC_IO (0x04) -#define SC_CD (0x02) -#define SC_MSG (0x01) - -#define AscGetVarFreeQHead( port ) AscReadLramWord( port, ASCV_FREE_Q_HEAD_W ) -#define AscGetVarDoneQTail( port ) AscReadLramWord( port, ASCV_DONE_Q_TAIL_W ) -#define AscPutVarFreeQHead( port, val ) AscWriteLramWord( port, ASCV_FREE_Q_HEAD_W, val ) -#define AscPutVarDoneQTail( port, val ) AscWriteLramWord( port, ASCV_DONE_Q_TAIL_W, val ) - -#define AscGetRiscVarFreeQHead( port ) AscReadLramByte( port, ASCV_NEXTRDY_B ) -#define AscGetRiscVarDoneQTail( port ) AscReadLramByte( port, ASCV_DONENEXT_B ) -#define AscPutRiscVarFreeQHead( port, val ) AscWriteLramByte( port, ASCV_NEXTRDY_B, val ) -#define AscPutRiscVarDoneQTail( port, val ) AscWriteLramByte( port, ASCV_DONENEXT_B, val ) - -#define AscGetChipIFC( port ) inp( (port)+IOP_REG_IFC ) -#define AscPutChipIFC( port, data ) outp( (port)+IOP_REG_IFC, data ) - -#define AscGetChipLramAddr( port ) ( ushort )inpw( ( PortAddr )((port)+IOP_RAM_ADDR) ) -#define AscSetChipLramAddr( port, addr ) outpw( ( PortAddr )( (port)+IOP_RAM_ADDR ), addr ) -#define AscPutChipLramData( port, data ) outpw( (port)+IOP_RAM_DATA, data ) -#define AscGetChipLramData( port ) inpw( (port)+IOP_RAM_DATA ) - -#define AscWriteChipSyn( port, data ) outp( (port)+IOP_SYN_OFFSET, data ) -#define AscReadChipSyn( port ) inp( (port)+IOP_SYN_OFFSET ) - -#define AscWriteChipIH( port, data ) outpw( (port)+IOP_REG_IH, data ) -#define AscReadChipIH( port ) inpw( (port)+IOP_REG_IH ) - -#define AscWriteChipScsiID( port, data ) outp( (port)+IOP_REG_ID, data ) -#define AscReadChipScsiID( port ) inp( (port)+IOP_REG_ID ) - -#define AscGetChipDmaSpeed( port ) ( uchar )inp( (port)+IOP_DMA_SPEED ) -#define AscSetChipDmaSpeed( port, data ) outp( (port)+IOP_DMA_SPEED, data ) -#define AscGetChipQP( port ) ( uchar )inp( (port)+IOP_REG_QP ) -#define AscSetPCAddr( port, data ) outpw( (port)+IOP_REG_PC, data ) -#define AscGetPCAddr( port ) inpw( (port)+IOP_REG_PC ) -#define AscGetChipVerNo( port ) ( uchar )inp( (port)+IOP_VERSION ) - -#define AscGetChipEEPCmd( port ) ( uchar )inp( (port)+IOP_EEP_CMD ) -#define AscSetChipEEPCmd( port, data ) outp( (port)+IOP_EEP_CMD, data ) -#define AscGetChipEEPData( port ) inpw( (port)+IOP_EEP_DATA ) -#define AscSetChipEEPData( port, data ) outpw( (port)+IOP_EEP_DATA, data ) - -#define AscGetChipControl( port ) ( uchar )inp( (port)+IOP_CTRL ) -#define AscSetChipControl( port, cc_val ) outp( (port)+IOP_CTRL, cc_val ) - -#define AscGetChipStatus( port ) ( ASC_CS_TYPE )inpw( (port)+IOP_STATUS ) -#define AscSetChipStatus( port, cs_val ) outpw( (port)+IOP_STATUS, cs_val ) - -#define AscGetChipCfgLsw( port ) ( ushort )inpw( (port)+IOP_CONFIG_LOW ) -#define AscGetChipCfgMsw( port ) ( ushort )inpw( (port)+IOP_CONFIG_HIGH ) -#define AscSetChipCfgLsw( port, data ) outpw( (port)+IOP_CONFIG_LOW, data ) -#define AscSetChipCfgMsw( port, data ) outpw( (port)+IOP_CONFIG_HIGH, data ) - -#define AscIsIntPending( port ) ( AscGetChipStatus( port ) & CSW_INT_PENDING ) -#define AscGetChipScsiID( port ) ( ( AscGetChipCfgLsw( port ) >> 8 ) & ASC_MAX_TID ) - +#define SC_SEL ( uchar )(0x80) +#define SC_BSY ( uchar )(0x40) +#define SC_ACK ( uchar )(0x20) +#define SC_REQ ( uchar )(0x10) +#define SC_ATN ( uchar )(0x08) +#define SC_IO ( uchar )(0x04) +#define SC_CD ( uchar )(0x02) +#define SC_MSG ( uchar )(0x01) +#define SEC_ACTIVE_NEGATE ( uchar )( 0x40 ) +#define SEC_SLEW_RATE ( uchar )( 0x20 ) #define ASC_HALT_EXTMSG_IN ( ushort )0x8000 #define ASC_HALT_CHK_CONDITION ( ushort )0x8100 #define ASC_HALT_SS_QUEUE_FULL ( ushort )0x8200 +#define ASC_HALT_DISABLE_ASYN_USE_SYN_FIX ( ushort )0x8300 +#define ASC_HALT_ENABLE_ASYN_USE_SYN_FIX ( ushort )0x8400 #define ASC_HALT_SDTR_REJECTED ( ushort )0x4000 - #define ASC_MAX_QNO 0xF8 #define ASC_DATA_SEC_BEG ( ushort )0x0080 #define ASC_DATA_SEC_END ( ushort )0x0080 @@ -1765,13 +1652,10 @@ #define ASC_QLAST_ADR ( ushort )0x7FC0 #define ASC_QBLK_SIZE 0x40 #define ASC_BIOS_DATA_QBEG 0xF8 - #define ASC_MIN_ACTIVE_QNO 0x01 - #define ASC_QLINK_END 0xFF #define ASC_EEPROM_WORDS 0x10 #define ASC_MAX_MGS_LEN 0x10 - #define ASC_BIOS_ADDR_DEF 0xDC00 #define ASC_BIOS_SIZE 0x3800 #define ASC_BIOS_RAM_OFF 0x3800 @@ -1779,19 +1663,14 @@ #define ASC_BIOS_MIN_ADDR 0xC000 #define ASC_BIOS_MAX_ADDR 0xEC00 #define ASC_BIOS_BANK_SIZE 0x0400 - #define ASC_MCODE_START_ADDR 0x0080 - #define ASC_CFG0_HOST_INT_ON 0x0020 #define ASC_CFG0_BIOS_ON 0x0040 #define ASC_CFG0_VERA_BURST_ON 0x0080 #define ASC_CFG0_SCSI_PARITY_ON 0x0800 - #define ASC_CFG1_SCSI_TARGET_ON 0x0080 #define ASC_CFG1_LRAM_8BITS_ON 0x0800 - -#define ASC_CFG_MSW_CLR_MASK 0xF0C0 - +#define ASC_CFG_MSW_CLR_MASK 0x30C0 #define CSW_TEST1 ( ASC_CS_TYPE )0x8000 #define CSW_AUTO_CONFIG ( ASC_CS_TYPE )0x4000 #define CSW_RESERVED1 ( ASC_CS_TYPE )0x2000 @@ -1802,24 +1681,18 @@ #define CSW_RESERVED2 ( ASC_CS_TYPE )0x0100 #define CSW_DMA_DONE ( ASC_CS_TYPE )0x0080 #define CSW_FIFO_RDY ( ASC_CS_TYPE )0x0040 - #define CSW_EEP_READ_DONE ( ASC_CS_TYPE )0x0020 - #define CSW_HALTED ( ASC_CS_TYPE )0x0010 #define CSW_SCSI_RESET_ACTIVE ( ASC_CS_TYPE )0x0008 - #define CSW_PARITY_ERR ( ASC_CS_TYPE )0x0004 #define CSW_SCSI_RESET_LATCH ( ASC_CS_TYPE )0x0002 - #define CSW_INT_PENDING ( ASC_CS_TYPE )0x0001 - +#define CIW_CLR_SCSI_RESET_INT ( ASC_CS_TYPE )0x1000 #define CIW_INT_ACK ( ASC_CS_TYPE )0x0100 #define CIW_TEST1 ( ASC_CS_TYPE )0x0200 #define CIW_TEST2 ( ASC_CS_TYPE )0x0400 #define CIW_SEL_33MHZ ( ASC_CS_TYPE )0x0800 - #define CIW_IRQ_ACT ( ASC_CS_TYPE )0x1000 - #define CC_CHIP_RESET ( uchar )0x80 #define CC_SCSI_RESET ( uchar )0x40 #define CC_HALT ( uchar )0x20 @@ -1828,11 +1701,9 @@ #define CC_TEST ( uchar )0x04 #define CC_BANK_ONE ( uchar )0x02 #define CC_DIAG ( uchar )0x01 - #define ASC_1000_ID0W 0x04C1 #define ASC_1000_ID0W_FIX 0x00C1 #define ASC_1000_ID1B 0x25 - #define ASC_EISA_BIG_IOP_GAP (0x1C30-0x0C50) #define ASC_EISA_SMALL_IOP_GAP (0x0020) #define ASC_EISA_MIN_IOP_ADDR (0x0C30) @@ -1840,17 +1711,13 @@ #define ASC_EISA_REV_IOP_MASK (0x0C83) #define ASC_EISA_PID_IOP_MASK (0x0C80) #define ASC_EISA_CFG_IOP_MASK (0x0C86) - #define ASC_GET_EISA_SLOT( iop ) ( PortAddr )( (iop) & 0xF000 ) - #define ASC_EISA_ID_740 0x01745004UL #define ASC_EISA_ID_750 0x01755004UL - #define INS_HALTINT ( ushort )0x6281 #define INS_HALT ( ushort )0x6280 #define INS_SINT ( ushort )0x6200 #define INS_RFLAG_WTM ( ushort )0x7380 - #define ASC_MC_SAVE_CODE_WSIZE 0x500 #define ASC_MC_SAVE_DATA_WSIZE 0x40 @@ -1859,6 +1726,76 @@ ushort code[ASC_MC_SAVE_CODE_WSIZE]; } ASC_MC_SAVED; +#define AscGetQDoneInProgress( port ) AscReadLramByte( (port), ASCV_Q_DONE_IN_PROGRESS_B ) +#define AscPutQDoneInProgress( port, val ) AscWriteLramByte( (port), ASCV_Q_DONE_IN_PROGRESS_B, val ) +#define AscGetVarFreeQHead( port ) AscReadLramWord( (port), ASCV_FREE_Q_HEAD_W ) +#define AscGetVarDoneQTail( port ) AscReadLramWord( (port), ASCV_DONE_Q_TAIL_W ) +#define AscPutVarFreeQHead( port, val ) AscWriteLramWord( (port), ASCV_FREE_Q_HEAD_W, val ) +#define AscPutVarDoneQTail( port, val ) AscWriteLramWord( (port), ASCV_DONE_Q_TAIL_W, val ) +#define AscGetRiscVarFreeQHead( port ) AscReadLramByte( (port), ASCV_NEXTRDY_B ) +#define AscGetRiscVarDoneQTail( port ) AscReadLramByte( (port), ASCV_DONENEXT_B ) +#define AscPutRiscVarFreeQHead( port, val ) AscWriteLramByte( (port), ASCV_NEXTRDY_B, val ) +#define AscPutRiscVarDoneQTail( port, val ) AscWriteLramByte( (port), ASCV_DONENEXT_B, val ) +#define AscPutMCodeSDTRDoneAtID( port, id, data ) AscWriteLramByte( (port), ( ushort )( ( ushort )ASCV_SDTR_DONE_BEG+( ushort )id ), (data) ) ; +#define AscGetMCodeSDTRDoneAtID( port, id ) AscReadLramByte( (port), ( ushort )( ( ushort )ASCV_SDTR_DONE_BEG+( ushort )id ) ) ; +#define AscPutMCodeInitSDTRAtID( port, id, data ) AscWriteLramByte( (port), ( ushort )( ( ushort )ASCV_SDTR_DATA_BEG+( ushort )id ), data ) ; +#define AscGetMCodeInitSDTRAtID( port, id ) AscReadLramByte( (port), ( ushort )( ( ushort )ASCV_SDTR_DATA_BEG+( ushort )id ) ) ; +#define AscSynIndexToPeriod( index ) ( uchar )( asc_dvc->sdtr_period_tbl[ (index) ] ) +#define AscGetChipSignatureByte( port ) ( uchar )inp( (port)+IOP_SIG_BYTE ) +#define AscGetChipSignatureWord( port ) ( ushort )inpw( (port)+IOP_SIG_WORD ) +#define AscGetChipVerNo( port ) ( uchar )inp( (port)+IOP_VERSION ) +#define AscGetChipCfgLsw( port ) ( ushort )inpw( (port)+IOP_CONFIG_LOW ) +#define AscGetChipCfgMsw( port ) ( ushort )inpw( (port)+IOP_CONFIG_HIGH ) +#define AscSetChipCfgLsw( port, data ) outpw( (port)+IOP_CONFIG_LOW, data ) +#define AscSetChipCfgMsw( port, data ) outpw( (port)+IOP_CONFIG_HIGH, data ) +#define AscGetChipEEPCmd( port ) ( uchar )inp( (port)+IOP_EEP_CMD ) +#define AscSetChipEEPCmd( port, data ) outp( (port)+IOP_EEP_CMD, data ) +#define AscGetChipEEPData( port ) ( ushort )inpw( (port)+IOP_EEP_DATA ) +#define AscSetChipEEPData( port, data ) outpw( (port)+IOP_EEP_DATA, data ) +#define AscGetChipLramAddr( port ) ( ushort )inpw( ( PortAddr )((port)+IOP_RAM_ADDR) ) +#define AscSetChipLramAddr( port, addr ) outpw( ( PortAddr )( (port)+IOP_RAM_ADDR ), addr ) +#define AscGetChipLramData( port ) ( ushort )inpw( (port)+IOP_RAM_DATA ) +#define AscSetChipLramData( port, data ) outpw( (port)+IOP_RAM_DATA, data ) +#define AscGetChipLramDataNoSwap( port ) ( ushort )inpw_noswap( (port)+IOP_RAM_DATA ) +#define AscSetChipLramDataNoSwap( port, data ) outpw_noswap( (port)+IOP_RAM_DATA, data ) +#define AscGetChipIFC( port ) ( uchar )inp( (port)+IOP_REG_IFC ) +#define AscSetChipIFC( port, data ) outp( (port)+IOP_REG_IFC, data ) +#define AscGetChipStatus( port ) ( ASC_CS_TYPE )inpw( (port)+IOP_STATUS ) +#define AscSetChipStatus( port, cs_val ) outpw( (port)+IOP_STATUS, cs_val ) +#define AscGetChipControl( port ) ( uchar )inp( (port)+IOP_CTRL ) +#define AscSetChipControl( port, cc_val ) outp( (port)+IOP_CTRL, cc_val ) +#define AscGetChipSyn( port ) ( uchar )inp( (port)+IOP_SYN_OFFSET ) +#define AscSetChipSyn( port, data ) outp( (port)+IOP_SYN_OFFSET, data ) +#define AscSetPCAddr( port, data ) outpw( (port)+IOP_REG_PC, data ) +#define AscGetPCAddr( port ) ( ushort )inpw( (port)+IOP_REG_PC ) +#define AscIsIntPending( port ) ( AscGetChipStatus(port) & ( CSW_INT_PENDING | CSW_SCSI_RESET_LATCH ) ) +#define AscGetChipScsiID( port ) ( ( AscGetChipCfgLsw(port) >> 8 ) & ASC_MAX_TID ) +#define AscGetExtraControl( port ) ( uchar )inp( (port)+IOP_EXTRA_CONTROL ) +#define AscSetExtraControl( port, data ) outp( (port)+IOP_EXTRA_CONTROL, data ) +#define AscReadChipAX( port ) ( ushort )inpw( (port)+IOP_REG_AX ) +#define AscWriteChipAX( port, data ) outpw( (port)+IOP_REG_AX, data ) +#define AscReadChipIX( port ) ( uchar )inp( (port)+IOP_REG_IX ) +#define AscWriteChipIX( port, data ) outp( (port)+IOP_REG_IX, data ) +#define AscReadChipIH( port ) ( ushort )inpw( (port)+IOP_REG_IH ) +#define AscWriteChipIH( port, data ) outpw( (port)+IOP_REG_IH, data ) +#define AscReadChipQP( port ) ( uchar )inp( (port)+IOP_REG_QP ) +#define AscWriteChipQP( port, data ) outp( (port)+IOP_REG_QP, data ) +#define AscReadChipFIFO_L( port ) ( ushort )inpw( (port)+IOP_REG_FIFO_L ) +#define AscWriteChipFIFO_L( port, data ) outpw( (port)+IOP_REG_FIFO_L, data ) +#define AscReadChipFIFO_H( port ) ( ushort )inpw( (port)+IOP_REG_FIFO_H ) +#define AscWriteChipFIFO_H( port, data ) outpw( (port)+IOP_REG_FIFO_H, data ) +#define AscReadChipDmaSpeed( port ) ( uchar )inp( (port)+IOP_DMA_SPEED ) +#define AscWriteChipDmaSpeed( port, data ) outp( (port)+IOP_DMA_SPEED, data ) +#define AscReadChipDA0( port ) ( ushort )inpw( (port)+IOP_REG_DA0 ) +#define AscWriteChipDA0( port ) outpw( (port)+IOP_REG_DA0, data ) +#define AscReadChipDA1( port ) ( ushort )inpw( (port)+IOP_REG_DA1 ) +#define AscWriteChipDA1( port ) outpw( (port)+IOP_REG_DA1, data ) +#define AscReadChipDC0( port ) ( ushort )inpw( (port)+IOP_REG_DC0 ) +#define AscWriteChipDC0( port ) outpw( (port)+IOP_REG_DC0, data ) +#define AscReadChipDC1( port ) ( ushort )inpw( (port)+IOP_REG_DC1 ) +#define AscWriteChipDC1( port ) outpw( (port)+IOP_REG_DC1, data ) +#define AscReadChipDvcID( port ) ( uchar )inp( (port)+IOP_REG_ID ) +#define AscWriteChipDvcID( port, data ) outp( (port)+IOP_REG_ID, data ) int AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg); int AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg); void AscWaitEEPRead(void); @@ -1869,17 +1806,14 @@ int AscSetEEPConfigOnce(PortAddr, ASCEEP_CONFIG dosfar *, ushort); int AscSetEEPConfig(PortAddr, ASCEEP_CONFIG dosfar *, ushort); ushort AscEEPSum(PortAddr, uchar, uchar); - int AscStartChip(PortAddr); int AscStopChip(PortAddr); void AscSetChipIH(PortAddr, ushort); -int AscSetRunChipSynRegAtID(PortAddr, uchar, uchar); - int AscIsChipHalted(PortAddr); - +void AscResetScsiBus(PortAddr); +int AscResetChip(PortAddr); void AscSetChipCfgDword(PortAddr, ulong); ulong AscGetChipCfgDword(PortAddr); - void AscAckInterrupt(PortAddr); void AscDisableInterrupt(PortAddr); void AscEnableInterrupt(PortAddr); @@ -1890,7 +1824,6 @@ ushort AscSetIsaDmaChannel(PortAddr, ushort); uchar AscSetIsaDmaSpeed(PortAddr, uchar); uchar AscGetIsaDmaSpeed(PortAddr); - uchar AscReadLramByte(PortAddr, ushort); ushort AscReadLramWord(PortAddr, ushort); ulong AscReadLramDWord(PortAddr, ushort); @@ -1900,33 +1833,26 @@ int AscVerWriteLramDWord(PortAddr, ushort, ulong); int AscVerWriteLramWord(PortAddr, ushort, ushort); int AscVerWriteLramByte(PortAddr, ushort, uchar); - -ulong AscMemSumLramWord(PortAddr, ushort, int); -void AscMemWordSetLram(PortAddr, ushort, ushort, int); +ulong AscMemSumLramWord(PortAddr, ushort, rint); +void AscMemWordSetLram(PortAddr, ushort, ushort, rint); void AscMemWordCopyToLram(PortAddr, ushort, ushort dosfar *, int); void AscMemDWordCopyToLram(PortAddr, ushort, ulong dosfar *, int); void AscMemWordCopyFromLram(PortAddr, ushort, ushort dosfar *, int); int AscMemWordCmpToLram(PortAddr, ushort, ushort dosfar *, int); - ushort AscInitAscDvcVar(ASC_DVC_VAR asc_ptr_type *); -ulong AscLoadMicroCode(PortAddr, ushort, - ushort dosfar *, ushort); ushort AscInitFromEEP(ASC_DVC_VAR asc_ptr_type *); +ushort AscInitWithoutEEP(ASC_DVC_VAR asc_ptr_type *); ushort AscInitFromAscDvcVar(ASC_DVC_VAR asc_ptr_type *); ushort AscInitMicroCodeVar(ASC_DVC_VAR asc_ptr_type * asc_dvc); - void dosfar AscInitPollIsrCallBack(ASC_DVC_VAR asc_ptr_type *, ASC_QDONE_INFO dosfar *); int AscTestExternalLram(ASC_DVC_VAR asc_ptr_type *); ushort AscTestLramEndian(PortAddr); - -uchar AscMsgOutSDTR(PortAddr, uchar, uchar); - -uchar AscCalSDTRData(uchar, uchar); +uchar AscMsgOutSDTR(ASC_DVC_VAR asc_ptr_type *, uchar, uchar); +uchar AscCalSDTRData(ASC_DVC_VAR asc_ptr_type *, uchar, uchar); void AscSetChipSDTR(PortAddr, uchar, uchar); int AscInitChipAllSynReg(ASC_DVC_VAR asc_ptr_type *, uchar); -uchar AscGetSynPeriodIndex(uchar); -uchar AscSynIndexToPeriod(uchar); +uchar AscGetSynPeriodIndex(ASC_DVC_VAR asc_ptr_type *, ruchar); uchar AscAllocFreeQueue(PortAddr, uchar); uchar AscAllocMultipleFreeQueue(PortAddr, uchar, uchar); int AscRiscHaltedAbortSRB(ASC_DVC_VAR asc_ptr_type *, ulong); @@ -1944,7 +1870,6 @@ int AscWaitTixISRDone(ASC_DVC_VAR asc_ptr_type *, uchar); int AscWaitISRDone(ASC_DVC_VAR asc_ptr_type *); ulong AscGetOnePhyAddr(ASC_DVC_VAR asc_ptr_type *, uchar dosfar *, ulong); - int AscSendScsiQueue(ASC_DVC_VAR asc_ptr_type * asc_dvc, ASC_SCSI_Q dosfar * scsiq, uchar n_q_required); @@ -1960,10 +1885,8 @@ ushort AscInitQLinkVar(ASC_DVC_VAR asc_ptr_type *); int AscSetLibErrorCode(ASC_DVC_VAR asc_ptr_type *, ushort); int _AscWaitQDone(PortAddr, ASC_SCSI_Q dosfar *); - int AscEnterCritical(void); void AscLeaveCritical(int); - int AscIsrChipHalted(ASC_DVC_VAR asc_ptr_type *); uchar _AscCopyLramScsiDoneQ(PortAddr, ushort, ASC_QDONE_INFO dosfar *, ulong); @@ -1971,7 +1894,6 @@ ushort AscIsrExeBusyQueue(ASC_DVC_VAR asc_ptr_type *, uchar); int AscScsiSetupCmdQ(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_REQ_Q dosfar *, uchar dosfar *, ulong); - int AscScsiInquiry(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_REQ_Q dosfar *, uchar dosfar *, int); int AscScsiTestUnitReady(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_REQ_Q dosfar *); @@ -1980,7 +1902,6 @@ int AscScsiReadCapacity(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_REQ_Q dosfar *, uchar dosfar *); - ulong dosfar *swapfarbuf4(uchar dosfar *); int PollQueueDone(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_REQ_Q dosfar *, @@ -1999,30 +1920,29 @@ void AscDispInquiry(uchar, uchar, ASC_SCSI_INQUIRY dosfar *); int AscPollQDone(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_REQ_Q dosfar *, int); - +int AscCompareString(uchar *, uchar *, int); int AscSetBIOSBank(PortAddr, int, ushort); int AscSetVlBIOSBank(PortAddr, int); int AscSetEisaBIOSBank(PortAddr, int); int AscSetIsaBIOSBank(PortAddr, int); - -int AscIsBiosEnabled(PortAddr, ushort); -void AscResetScsiBus(PortAddr); +ushort AscGetEisaChipCfg(PortAddr); +ushort AscGetEisaChipGpReg(PortAddr); +ushort AscSetEisaChipCfg(PortAddr, ushort); +ushort AscSetEisaChipGpReg(PortAddr, ushort); +ulong AscGetEisaProductID(PortAddr); +PortAddr AscSearchIOPortAddrEISA(PortAddr); void AscClrResetScsiBus(PortAddr); - -void AscSingleStepChip(PortAddr); +uchar AscGetChipScsiCtrl(PortAddr); uchar AscSetChipScsiID(PortAddr, uchar); -ushort AscGetChipBiosAddress(PortAddr, ushort); -ushort AscSetChipBiosAddress(PortAddr, ushort, ushort); uchar AscGetChipVersion(PortAddr, ushort); ushort AscGetChipBusType(PortAddr); - +ulong AscLoadMicroCode(PortAddr, ushort, + ushort dosfar *, ushort); +int AscFindSignature(PortAddr); PortAddr AscSearchIOPortAddr11(PortAddr); PortAddr AscSearchIOPortAddr100(PortAddr); -int AscFindSignature(PortAddr); void AscToggleIRQAct(PortAddr); -int AscResetChip(PortAddr); void AscClrResetChip(PortAddr); - short itos(ushort, uchar dosfar *, short, short); int insnchar(uchar dosfar *, short, short, ruchar, short); void itoh(ushort, ruchar dosfar *); @@ -2032,55 +1952,46 @@ uchar dosfar *tohstr(ushort, uchar dosfar *); uchar dosfar *tobhstr(uchar, uchar dosfar *); uchar dosfar *tolhstr(ulong, uchar dosfar *); - void AscSetISAPNPWaitForKey(void); uchar AscGetChipIRQ(PortAddr, ushort); uchar AscSetChipIRQ(PortAddr, uchar, ushort); -uchar AscGetChipScsiCtrl(PortAddr); - -ushort AscGetEisaChipCfg(PortAddr); -ushort AscGetEisaChipGpReg(PortAddr); -ushort AscSetEisaChipCfg(PortAddr, ushort); -ushort AscSetEisaChipGpReg(PortAddr, ushort); - -ulong AscGetEisaProductID(PortAddr); -PortAddr AscSearchIOPortAddrEISA(PortAddr); - +int AscIsBiosEnabled(PortAddr, ushort); +int AscEnableBios(PortAddr, ushort); +ushort AscGetChipBiosAddress(PortAddr, ushort); +ushort AscSetChipBiosAddress(PortAddr, ushort, ushort); +void AscSingleStepChip(PortAddr); int AscPollQTailSync(PortAddr); int AscPollQHeadSync(PortAddr); int AscWaitQTailSync(PortAddr); - int _AscRestoreMicroCode(PortAddr, ASC_MC_SAVED dosfar *); - int AscSCAM(ASC_DVC_VAR asc_ptr_type *); - ushort SwapByteOfWord(ushort word_val); ulong SwapWordOfDWord(ulong dword_val); ulong AdjEndianDword(ulong dword_val); - int AscAdjEndianScsiQ(ASC_SCSI_Q dosfar *); int AscAdjEndianQDoneInfo(ASC_QDONE_INFO dosfar *); - +int AscCoalesceSgList(ASC_SCSI_Q dosfar *); extern int DvcEnterCritical(void); extern void DvcLeaveCritical(int); - +extern void DvcSetMemory(uchar dosfar *, uint, uchar); +extern void DvcCopyMemory(uchar dosfar *, uchar dosfar *, uint); extern void DvcInPortWords(PortAddr, ushort dosfar *, int); extern void DvcOutPortWords(PortAddr, ushort dosfar *, int); extern void DvcOutPortDWords(PortAddr, ulong dosfar *, int); - +extern uchar DvcReadPCIConfigByte(ASC_DVC_VAR asc_ptr_type *, ushort); +extern void DvcWritePCIConfigByte(ASC_DVC_VAR asc_ptr_type *, ushort, uchar); +ushort AscGetChipBiosAddress(PortAddr, ushort); extern void DvcSleepMilliSecond(ulong); +extern void DvcDelayNanoSecond(ASC_DVC_VAR asc_ptr_type *, ulong); extern void DvcDisplayString(uchar dosfar *); extern ulong DvcGetPhyAddr(uchar dosfar * buf_addr, ulong buf_len); extern ulong DvcGetSGList(ASC_DVC_VAR asc_ptr_type *, uchar dosfar *, ulong, ASC_SG_HEAD dosfar *); - extern void DvcSCAMDelayMS(ulong); extern int DvcDisableCPUInterrupt(void); extern void DvcRestoreCPUInterrupt(int); - void DvcPutScsiQ(PortAddr, ushort, ushort dosfar *, int); void DvcGetQinfo(PortAddr, ushort, ushort dosfar *, int); - PortAddr AscSearchIOPortAddr(PortAddr, ushort); ushort AscInitGetConfig(ASC_DVC_VAR asc_ptr_type *); ushort AscInitSetConfig(ASC_DVC_VAR asc_ptr_type *); @@ -2097,34 +2008,27 @@ ASC_SCSI_INQUIRY dosfar *, ASC_CAP_INFO dosfar *); int AscExeScsiQueue(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_Q dosfar *); - int AscISR(ASC_DVC_VAR asc_ptr_type *); void AscISR_AckInterrupt(ASC_DVC_VAR asc_ptr_type *); int AscISR_CheckQDone(ASC_DVC_VAR asc_ptr_type *, ASC_QDONE_INFO dosfar *, uchar dosfar *); - int AscStartUnit(ASC_DVC_VAR asc_ptr_type *, ASC_SCSI_TIX_TYPE); int AscStopUnit( ASC_DVC_VAR asc_ptr_type * asc_dvc, ASC_SCSI_TIX_TYPE target_ix ); - uint AscGetNumOfFreeQueue(ASC_DVC_VAR asc_ptr_type *, uchar, uchar); int AscSgListToQueue(int); int AscQueueToSgList(int); int AscSetDvcErrorCode(ASC_DVC_VAR asc_ptr_type *, uchar); - int AscAbortSRB(ASC_DVC_VAR asc_ptr_type *, ulong); int AscResetDevice(ASC_DVC_VAR asc_ptr_type *, uchar); int AscResetSB(ASC_DVC_VAR asc_ptr_type *); - void AscEnableIsaDma(uchar); void AscDisableIsaDma(uchar); - ulong AscGetMaxDmaAddress(ushort); ulong AscGetMaxDmaCount(ushort); - int AscSaveMicroCode(ASC_DVC_VAR asc_ptr_type *, ASC_MC_SAVED dosfar *); int AscRestoreOldMicroCode(ASC_DVC_VAR asc_ptr_type *, ASC_MC_SAVED dosfar *); int AscRestoreNewMicroCode(ASC_DVC_VAR asc_ptr_type *, ASC_MC_SAVED dosfar *); @@ -2148,13 +2052,27 @@ #define ASC_NUM_BUS 4 /* Reference Scsi_Host hostdata */ -#define ASC_BOARD(host) ((struct asc_board *) &(host)->hostdata) +#define ASC_BOARDP(host) ((struct asc_board *) &((host)->hostdata)) -#define NO_ISA_DMA 0xff /* No ISA DMA Channel Used */ +#define NO_ISA_DMA 0xff /* No ISA DMA Channel Used */ -#ifndef min -#define min(a, b) (((a) < (b)) ? (a) : (b)) -#endif /* min */ +#define ASC_INFO_SIZE 128 /* advansys_info() line size */ + +/* /proc/scsi/advansys/[0...] related definitions */ +#define ASC_PRTBUF_SIZE 1024 +#define ASC_PRTLINE_SIZE 160 + +#define ASC_PRT_NEXT() \ + if (cp) { \ + totlen += len; \ + leftlen -= len; \ + if (leftlen == 0) { \ + return totlen; \ + } \ + cp += len; \ + } + +#define ASC_MIN(a, b) (((a) < (b)) ? (a) : (b)) /* Asc Library return codes */ #define ASC_TRUE 1 @@ -2169,17 +2087,23 @@ #define HOST_BYTE(byte) ((byte) << 16) #define DRIVER_BYTE(byte) ((byte) << 24) +/* + * REQ and REQP are the generic name for a SCSI request block and pointer. + * REQPTID(reqp) returns reqp's target id. + * REQPNEXT(reqp) returns reqp's next pointer. + * REQPNEXTP(reqp) returns a pointer to reqp's next pointer. + */ +typedef Scsi_Cmnd REQ, *REQP; +#define REQPNEXT(reqp) ((REQP) ((reqp)->host_scribble)) +#define REQPNEXTP(reqp) ((REQP *) &((reqp)->host_scribble)) +#define REQPTID(reqp) ((reqp)->target) + /* asc_enqueue() flags */ #define ASC_FRONT 1 #define ASC_BACK 2 /* PCI configuration declarations */ -#define ASC_PCI_REV_A_INIT 0x01 -#define ASC_PCI_REV_A_DONE 0x02 -#define ASC_PCI_REV_B_INIT 0x04 -#define ASC_PCI_REV_B_DONE 0x08 - #define PCI_BASE_CLASS_PREDEFINED 0x00 #define PCI_BASE_CLASS_MASS_STORAGE 0x01 #define PCI_BASE_CLASS_NETWORK 0x02 @@ -2227,8 +2151,11 @@ #define PCI_MAX_SLOT 0x1F #define PCI_MAX_BUS 0xFF -#define ASC_PCI_VENDORID 0x10CD #define PCI_IOADDRESS_MASK 0xFFFE +#define ASC_PCI_VENDORID 0x10CD +#define ASC_PCI_DEVICE_ID_1100 0x1100 +#define ASC_PCI_DEVICE_ID_1200 0x1200 +#define ASC_PCI_DEVICE_ID_1300 0x1300 /* PCI IO Port Addresses to generate special cycle */ @@ -2249,18 +2176,54 @@ #define VENDORID_OFFSET 0x00 #define DEVICEID_OFFSET 0x02 -/* - * --- Driver Macros - */ - #ifndef ADVANSYS_STATS -#define ASC_STATS(counter) -#define ASC_STATS_ADD(counter, count) +#define ASC_STATS(shp, counter) +#define ASC_STATS_ADD(shp, counter, count) #else /* ADVANSYS_STATS */ -#define ASC_STATS(counter) asc_stats.counter++ -#define ASC_STATS_ADD(counter, count) asc_stats.counter += (count) +#define ASC_STATS(shp, counter) \ + (ASC_BOARDP(shp)->asc_stats.counter++) + +#define ASC_STATS_ADD(shp, counter, count) \ + (ASC_BOARDP(shp)->asc_stats.counter += (count)) #endif /* ADVANSYS_STATS */ +#define ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit)) +#define ASC_TENTHS(num, den) ((((num) * 10)/(den)) - (10 * ((num)/(den)))) + +/* + * Display a message to the console. + */ +#define ASC_PRINT(s) \ + { \ + printk("advansys: "); \ + printk(s); \ + } + +#define ASC_PRINT1(s, a1) \ + { \ + printk("advansys: "); \ + printk((s), (a1)); \ + } + +#define ASC_PRINT2(s, a1, a2) \ + { \ + printk("advansys: "); \ + printk((s), (a1), (a2)); \ + } + +#define ASC_PRINT3(s, a1, a2, a3) \ + { \ + printk("advansys: "); \ + printk((s), (a1), (a2), (a3)); \ + } + +#define ASC_PRINT4(s, a1, a2, a3, a4) \ + { \ + printk("advansys: "); \ + printk((s), (a1), (a2), (a3), (a4)); \ + } + + #ifndef ADVANSYS_DEBUG #define ASC_DBG(lvl, s) @@ -2388,6 +2351,48 @@ * --- Driver Structures */ +#ifdef ADVANSYS_STATS + +/* Per board statistics structure */ +struct asc_stats { + /* Driver Entrypoint Statistics */ + ulong command; /* # calls to advansys_command() */ + ulong queuecommand; /* # calls to advansys_queuecommand() */ + ulong abort; /* # calls to advansys_abort() */ + ulong reset; /* # calls to advansys_reset() */ + ulong biosparam; /* # calls to advansys_biosparam() */ + ulong check_interrupt;/* # advansys_interrupt() check pending calls */ + ulong interrupt; /* # advansys_interrupt() interrupts */ + ulong callback; /* # calls asc_isr_callback() */ + /* AscExeScsiQueue() Statistics */ + ulong asc_noerror; /* # AscExeScsiQueue() ASC_NOERROR returns. */ + ulong asc_busy; /* # AscExeScsiQueue() ASC_BUSY returns. */ + ulong asc_error; /* # AscExeScsiQueue() ASC_ERROR returns. */ + ulong asc_unknown; /* # AscExeScsiQueue() unknown returns. */ + /* Data Transfer Statistics */ + ulong cont_cnt; /* # non-scatter-gather I/O requests received */ + ulong cont_xfer; /* # contiguous transfer 512-bytes */ + ulong sg_cnt; /* # scatter-gather I/O requests received */ + ulong sg_elem; /* # scatter-gather elements */ + ulong sg_xfer; /* # scatter-gather tranfer 512-bytes */ + /* Device SCSI Command Queuing Statistics */ + ASC_SCSI_BIT_ID_TYPE queue_full; + ushort queue_full_cnt[ASC_MAX_TID+1]; +}; +#endif /* ADVANSYS_STATS */ + +/* + * Request queuing structure + */ +typedef struct asc_queue { + ASC_SCSI_BIT_ID_TYPE tidmask; /* queue mask */ + REQP queue[ASC_MAX_TID+1]; /* queue linked list */ +#ifdef ADVANSYS_STATS + short cur_count[ASC_MAX_TID+1]; /* current queue count */ + short max_count[ASC_MAX_TID+1]; /* maximum queue count */ +#endif /* ADVANSYS_STATS */ +} asc_queue_t; + /* * Structure allocated for each board. * @@ -2396,18 +2401,26 @@ * field. It is guaranteed to be allocated from DMA-able memory. */ struct asc_board { + int id; /* Board Id */ /* Asc Library */ - ASC_DVC_VAR board; /* Board configuration */ - ASC_DVC_CFG cfg; /* Device configuration */ - uchar overrun_buf[ASC_OVERRUN_BSIZE]; + ASC_DVC_VAR asc_dvc_var; /* Board configuration */ + ASC_DVC_CFG asc_dvc_cfg; /* Device configuration */ /* Queued Commands */ - ASC_SCSI_BIT_ID_TYPE pending_tidmask; /* Pending command mask */ - Scsi_Cmnd *pending[ASC_MAX_TID]; + asc_queue_t active; /* Active command queue */ + asc_queue_t pending; /* Pending command queue */ /* Target Initialization */ - ASC_SCSI_BIT_ID_TYPE init_tidmask; /* Target initialized mask */ + ASC_SCSI_BIT_ID_TYPE init_tidmask; /* Target initialized mask */ ASC_SCSI_REQ_Q scsireqq; ASC_CAP_INFO cap_info; ASC_SCSI_INQUIRY inquiry; + ASCEEP_CONFIG eep_config; /* EEPROM configuration */ +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + /* /proc/scsi/advansys/[0...] */ + char *prtbuf; /* Statistics Print Buffer */ +#endif /* version >= v1.3.0 */ +#ifdef ADVANSYS_STATS + struct asc_stats asc_stats; /* Board statistics */ +#endif /* ADVANSYS_STATS */ }; /* @@ -2459,48 +2472,14 @@ uchar maxLatency; } PCI_CONFIG_SPACE; -#ifdef ADVANSYS_STATS -struct asc_stats { - ulong command; /* # calls to advansys_command() */ - ulong queuecommand; /* # calls to advansys_queuecommand() */ - ulong abort; /* # calls to advansys_abort() */ - ulong reset; /* # calls to advansys_reset() */ - ulong biosparam; /* # calls to advansys_biosparam() */ - ulong interrupt; /* # calls to advansys_interrupt() */ - ulong callback; /* # calls asc_isr_callback() */ - ulong cont_cnt; /* # non-scatter-gather I/O requests received */ - ulong cont_xfer; /* contiguous transfer total (512 byte units) */ - ulong sg_cnt; /* # scatter-gather I/O requests received */ - ulong sg_elem; /* scatter-gather element total */ - ulong sg_xfer; /* scatter-gather transfer total (512 byte units) */ - ulong error; /* # AscExeScsiQueue() ASC_ERROR returns. */ - /* - * Number of times interrupts disabled in advansys_queuecommand() and - * asc_isr_callback(), respectively. For the former indicates how many - * times commands were pending when a new command was received. - */ - ulong cmd_disable; - ulong intr_disable; - /* - * Number of times asc_enqueue() called. Indicates how many ASC_BUSY - * returns have occurred. - */ - ulong enqueue; - ulong dequeue; /* # calls to asc_dequeue(). */ - /* - * Number of times asc_rmqueue() called and the specified command - * was found and removed. - */ - ulong rmqueue; -} asc_stats; -#endif /* ADVANSYS_STATS */ - /* * --- Driver Data */ -#ifdef LINUX_1_3 +/* Note: All driver global data should be initialized. */ + +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) struct proc_dir_entry proc_scsi_advansys = { PROC_SCSI_ADVANSYS, /* unsigned short low_ino */ @@ -2509,12 +2488,19 @@ S_IFDIR | S_IRUGO | S_IXUGO, /* mode_t mode */ 2 /* nlink_t nlink */ }; -#endif /* LINUX_1_3 */ +#endif /* version >= v1.3.0 */ + +/* Number of boards detected in system. */ +STATIC int asc_board_count = 0; +STATIC struct Scsi_Host *asc_host[ASC_NUM_BOARD_SUPPORTED] = { 0 }; -STATIC int asc_board_count; /* Number of boards detected in system. */ -STATIC struct Scsi_Host *asc_host[ASC_NUM_BOARD_SUPPORTED]; -STATIC Scsi_Cmnd *asc_scsi_done; /* Commands needing done function call. */ +/* Global list of commands needing done function. */ +STATIC Scsi_Cmnd *asc_scsi_done = NULL; +/* Overrun buffer shared between all boards. */ +STATIC uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 }; + +/* List of supported bus types. */ STATIC ushort asc_bus[ASC_NUM_BUS] = { ASC_IS_ISA, ASC_IS_VL, @@ -2522,6 +2508,8 @@ ASC_IS_PCI, }; +STATIC int pci_scan_method = -1; + /* * Used with the LILO 'advansys' option to eliminate or * limit I/O port probing at boot time, cf. advansys_setup(). @@ -2548,45 +2536,55 @@ * advansys.h contains function prototypes for functions global to Linux. */ -#ifdef LINUX_1_3 +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) STATIC int asc_proc_copy(off_t, off_t, char *, int , char *, int); -#endif /* LINUX_1_3 */ -#ifdef LINUX_1_2 +#endif /* version >= v1.3.0 */ +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70) STATIC void advansys_interrupt(int, struct pt_regs *); -#else /* LINUX_1_3 */ +#else /* version >= v1.3.70 */ STATIC void advansys_interrupt(int, void *, struct pt_regs *); -#endif /* LINUX_1_3 */ +#endif /* version >= v1.3.70 */ +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) +STATIC void advansys_select_queue_depths(struct Scsi_Host *, + Scsi_Device *); +#endif /* version >= v1.3.89 */ STATIC void advansys_command_done(Scsi_Cmnd *); STATIC int asc_execute_scsi_cmnd(Scsi_Cmnd *); STATIC void asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *); -STATIC void asc_execute_pending(struct Scsi_Host *); STATIC int asc_init_dev(ASC_DVC_VAR *, Scsi_Cmnd *); STATIC int asc_srch_pci_dev(PCI_DEVICE *); -STATIC uchar asc_scan_method(PCI_DEVICE *); +STATIC uchar asc_scan_method(void); STATIC int asc_pci_find_dev(PCI_DEVICE *); STATIC void asc_get_pci_cfg(PCI_DEVICE *, PCI_CONFIG_SPACE *); STATIC ushort asc_get_cfg_word(PCI_DATA *); STATIC uchar asc_get_cfg_byte(PCI_DATA *); -STATIC void asc_enqueue(struct Scsi_Host *, Scsi_Cmnd *, int, int); -STATIC Scsi_Cmnd *asc_dequeue(struct Scsi_Host *, int); -STATIC int asc_rmqueue(struct Scsi_Host *, Scsi_Cmnd *, int); +STATIC void asc_put_cfg_byte(PCI_DATA *, uchar); +void asc_enqueue(asc_queue_t *, REQP, int); +REQP asc_dequeue(asc_queue_t *, int); +int asc_rmqueue(asc_queue_t *, REQP); +int asc_isqueued(asc_queue_t *, REQP); +void asc_execute_queue(asc_queue_t *); +STATIC int asc_prt_board_devices(struct Scsi_Host *, char *, int); +STATIC int asc_prt_board_eeprom(struct Scsi_Host *, char *, int); +STATIC int asc_prt_board_info(struct Scsi_Host *, char *, int); +STATIC int asc_proc_copy(off_t, off_t, char *, int , char *, int); +STATIC int asc_prt_line(char *, int, char *fmt, ...); /* XXX - Asc Library Routines not supposed to be used directly */ -ushort AscGetChipBiosAddress(PortAddr, ushort); -int AscFindSignature(PortAddr); +int AscFindSignature(PortAddr); +ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort); #ifdef ADVANSYS_STATS -STATIC int asc_prt_stats(char *, int); -STATIC int asc_prt_stats_line(char *, int, char *fmt, ...); +STATIC int asc_prt_board_stats(struct Scsi_Host *, char *, int); #endif /* ADVANSYS_STATS */ #ifdef ADVANSYS_DEBUG -STATIC void asc_prt_scsi_host(struct Scsi_Host *); -STATIC void asc_prt_dvc_cfg(ASC_DVC_CFG *); -STATIC void asc_prt_dvc_var(ASC_DVC_VAR *); -STATIC void asc_prt_scsi_q(ASC_SCSI_Q *); -STATIC void asc_prt_qdone_info(ASC_QDONE_INFO *); -STATIC void asc_prt_hex(char *f, uchar *, int); -STATIC int interrupts_enabled(void); +STATIC void asc_prt_scsi_host(struct Scsi_Host *); +STATIC void asc_prt_dvc_cfg(ASC_DVC_CFG *); +STATIC void asc_prt_dvc_var(ASC_DVC_VAR *); +STATIC void asc_prt_scsi_q(ASC_SCSI_Q *); +STATIC void asc_prt_qdone_info(ASC_QDONE_INFO *); +STATIC void asc_prt_hex(char *f, uchar *, int); +STATIC int interrupts_enabled(void); #endif /* ADVANSYS_DEBUG */ @@ -2594,25 +2592,33 @@ * --- Linux 'Scsi_Host_Template' and advansys_setup() Functions */ -#ifdef LINUX_1_3 +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) /* * advansys_proc_info() - /proc/scsi/advansys/[0-(ASC_NUM_BOARD_SUPPORTED-1)] * * *buffer: I/O buffer * **start: if inout == FALSE pointer into buffer where user read should start - * offset: current offset into /proc/scsi/advansys file + * offset: current offset into a /proc/scsi/advansys/[0...] file * length: length of buffer * hostno: Scsi_Host host_no * inout: TRUE - user is writing; FALSE - user is reading * - * Return the number of bytes read from or written to - * /proc/scsi/advansys file. + * Return the number of bytes read from or written to a + * /proc/scsi/advansys/[0...] file. + * + * Note: This function uses the per board buffer 'prtbuf' which is + * allocated when the board is initialized in advansys_detect(). The + * buffer is ASC_PRTBUF_SIZE bytes. The function asc_proc_copy() is + * used to write to the buffer. The way asc_proc_copy() is written + * if 'prtbuf' is too small it will not be overwritten. Instead the + * user just won't get all the available statistics. */ int advansys_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) { struct Scsi_Host *shp; + struct asc_board *boardp; int i; char *cp; int cplen; @@ -2622,7 +2628,6 @@ char *curbuf; off_t advoffset; Scsi_Device *scd; - char prtbuf[480]; /* 6 lines */ ASC_DBG(1, "advansys_proc_info: begin\n"); @@ -2634,7 +2639,7 @@ } /* - * User read of /proc/scsi/advansys file. + * User read of /proc/scsi/advansys/[0...] file. */ /* Find the specified board. */ @@ -2646,21 +2651,25 @@ if (i == asc_board_count) { return(-ENOENT); } + shp = asc_host[i]; + boardp = ASC_BOARDP(shp); - /* Always copy read data to the beginning of the buffer. */ + /* Copy read data starting at the beginning of the buffer. */ *start = buffer; - curbuf = buffer; advoffset = 0; totcnt = 0; leftlen = length; - /* Get board information. */ + /* + * Get board configuration information. + * + * advansys_info() returns the board string from its own static buffer. + */ cp = (char *) advansys_info(shp); strcat(cp, "\n"); cplen = strlen(cp); - /* Copy board information. */ cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); totcnt += cnt; @@ -2673,11 +2682,11 @@ curbuf += cnt; /* - * Get and copy information for each device attached to the board. + * Display driver information for each device attached to the board. */ - cp = &prtbuf[0]; - sprintf(cp, "\nDevices attached to SCSI Host %d:\n", shp->host_no); - cplen = strlen(cp); + cp = boardp->prtbuf; + cplen = asc_prt_board_devices(shp, cp, ASC_PRTBUF_SIZE); + ASC_ASSERT(cplen < ASC_PRTBUF_SIZE); cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); totcnt += cnt; leftlen -= cnt; @@ -2688,10 +2697,19 @@ advoffset += cplen; curbuf += cnt; - cp = &prtbuf[0]; + /* + * Display target driver information for each device attached + * to the board. + */ for (scd = scsi_devices; scd; scd = scd->next) { if (scd->host == shp) { + cp = boardp->prtbuf; + /* + * Note: If proc_print_scsidevice() writes more than + * ASC_PRTBUF_SIZE bytes, it will overrun 'prtbuf'. + */ proc_print_scsidevice(scd, cp, &cplen, 0); + ASC_ASSERT(cplen < ASC_PRTBUF_SIZE); cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); totcnt += cnt; leftlen -= cnt; @@ -2704,15 +2722,29 @@ } } + /* + * Display EEPROM configuration for the board. + */ + cp = boardp->prtbuf; + cplen = asc_prt_board_eeprom(shp, cp, ASC_PRTBUF_SIZE); + ASC_ASSERT(cplen < ASC_PRTBUF_SIZE); + cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); + totcnt += cnt; + leftlen -= cnt; + if (leftlen == 0) { + ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); + return totcnt; + } + advoffset += cplen; + curbuf += cnt; + #ifdef ADVANSYS_STATS /* - * prtbuf[] has about 6 lines worth of space. If the statistics ever - * get longer than 6 lines, prtbuf[] should be increased in size. If - * prtbuf[] is too small it will not be overwritten. Instead the user - * just won't get all of the available statistics. + * Display driver statistics for the board. */ - cp = &prtbuf[0]; - cplen = asc_prt_stats(cp, sizeof(prtbuf)); + cp = boardp->prtbuf; + cplen = asc_prt_board_stats(shp, cp, ASC_PRTBUF_SIZE); + ASC_ASSERT(cplen < ASC_PRTBUF_SIZE); cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); totcnt += cnt; leftlen -= cnt; @@ -2724,11 +2756,28 @@ curbuf += cnt; #endif /* ADVANSYS_STATS */ + /* + * Display Asc Library dynamic configuration information + * for the board. + */ + cp = boardp->prtbuf; + cplen = asc_prt_board_info(shp, cp, ASC_PRTBUF_SIZE); + ASC_ASSERT(cplen < ASC_PRTBUF_SIZE); + cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); + totcnt += cnt; + leftlen -= cnt; + if (leftlen == 0) { + ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); + return totcnt; + } + advoffset += cplen; + curbuf += cnt; + ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt); return totcnt; } -#endif /* LINUX_1_3 */ +#endif /* version >= v1.3.0 */ /* @@ -2751,8 +2800,10 @@ int iop; int bus; struct Scsi_Host *shp; - ASC_DVC_VAR *boardp; + struct asc_board *boardp; + ASC_DVC_VAR *asc_dvc_varp; int ioport = 0; + int share_irq = FALSE; PCI_DEVICE pciDevice; PCI_CONFIG_SPACE pciConfig; int ret; @@ -2762,19 +2813,15 @@ if (detect_called == ASC_FALSE) { detect_called = ASC_TRUE; } else { - printk("AdvanSys SCSI: advansys_detect() multiple calls ignored\n"); + printk("AdvanSys SCSI: advansys_detect() mulitple calls ignored\n"); return 0; } ASC_DBG(1, "advansys_detect: begin\n"); -#ifdef LINUX_1_3 +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) tpnt->proc_dir = &proc_scsi_advansys; -#endif /* LINUX_1_3 */ - -#ifdef ADVANSYS_STATS - memset(&asc_stats, 0, sizeof(asc_stats)); -#endif /* ADVANSYS_STATS */ +#endif /* version >= v1.3.0 */ asc_board_count = 0; @@ -2899,7 +2946,8 @@ break; default: - ASC_DBG(0, "advansys_detect: unknown bus type\n"); + ASC_PRINT1("advansys_detect: unknown bus type: %d\n", + asc_bus[bus]); break; } ASC_DBG1(1, "advansys_detect: iop %x\n", iop); @@ -2920,106 +2968,192 @@ ASC_DBG(2, "advansys_detect: scsi_register()\n"); shp = scsi_register(tpnt, sizeof(struct asc_board)); - /* Save a pointer to the Scsi_host of each found board. */ + /* Save a pointer to the Scsi_host of each board found. */ asc_host[asc_board_count++] = shp; /* Initialize private per board data */ - memset(ASC_BOARD(shp), 0, sizeof(struct asc_board)); - boardp = &ASC_BOARD(shp)->board; - boardp->cfg = &ASC_BOARD(shp)->cfg; - boardp->cfg->overrun_buf = &ASC_BOARD(shp)->overrun_buf[0]; - boardp->iop_base = iop; + boardp = ASC_BOARDP(shp); + memset(boardp, 0, sizeof(struct asc_board)); + boardp->id = asc_board_count - 1; + asc_dvc_varp = &boardp->asc_dvc_var; + asc_dvc_varp->cfg = &boardp->asc_dvc_cfg; + asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0]; + asc_dvc_varp->iop_base = iop; + +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + if ((boardp->prtbuf = + kmalloc(ASC_PRTBUF_SIZE, GFP_ATOMIC)) == NULL) { + ASC_PRINT3( +"advansys_detect: Board %d: kmalloc(%d, %d) returned NULL\n", + boardp->id, ASC_PRTBUF_SIZE, GFP_ATOMIC); + scsi_unregister(shp); + asc_board_count--; + continue; + } +#endif /* version >= v1.3.0 */ /* * Set the board bus type and PCI IRQ for AscInitGetConfig(). */ - boardp->bus_type = asc_bus[bus]; - switch (boardp->bus_type) { + asc_dvc_varp->bus_type = asc_bus[bus]; + switch (asc_dvc_varp->bus_type) { case ASC_IS_ISA: shp->unchecked_isa_dma = TRUE; + share_irq = FALSE; break; - case ASC_IS_EISA: + case ASC_IS_VL: shp->unchecked_isa_dma = FALSE; + share_irq = FALSE; break; - case ASC_IS_VL: + case ASC_IS_EISA: shp->unchecked_isa_dma = FALSE; + share_irq = TRUE; break; case ASC_IS_PCI: - shp->irq = boardp->irq_no = pciConfig.irqLine; - boardp->cfg->pci_device_id = pciConfig.deviceID; + shp->irq = asc_dvc_varp->irq_no = pciConfig.irqLine; + asc_dvc_varp->cfg->pci_device_id = pciConfig.deviceID; + asc_dvc_varp->cfg->pci_slot_info = + ASC_PCI_MKID(pciDevice.busNumber, + pciDevice.slotFound, + pciDevice.devFunc); shp->unchecked_isa_dma = FALSE; + share_irq = TRUE; break; default: - ASC_DBG(0, "advansys_detect: unknown adapter type"); + ASC_PRINT2( +"advansys_detect: Board %d: unknown adapter type: %d", + boardp->id, asc_dvc_varp->bus_type); shp->unchecked_isa_dma = TRUE; + share_irq = FALSE; break; } /* - * Get the board configuration. AscInitGetConfig() may change - * the board's bus_type value. The asc_bus[bus] value should no - * longer be used. + * Get the board configuration. + * + * AscInitGetConfig() may change the board's bus_type value. + * The asc_bus[bus] value should no longer be used. If the + * bus_type field must be referenced only use the bit-wise + * AND operator "&". */ ASC_DBG(2, "advansys_detect: AscInitGetConfig()\n"); - switch(ret = AscInitGetConfig(boardp)) { + switch(ret = AscInitGetConfig(asc_dvc_varp)) { case 0: /* No error */ break; case ASC_WARN_IO_PORT_ROTATE: - ASC_DBG(0, "AscInitGetConfig: I/O port address modified\n"); + ASC_PRINT1( +"AscInitGetConfig: Board: %d: I/O port address modified\n", + boardp->id); + break; + case ASC_WARN_AUTO_CONFIG: + ASC_PRINT1( +"AscInitGetConfig: Board %d: I/O port increment switch enabled\n", + boardp->id); break; case ASC_WARN_EEPROM_CHKSUM: - ASC_DBG(0, "AscInitGetConfig: EEPROM checksum error\n"); + ASC_PRINT1( +"AscInitGetConfig: Board %d: EEPROM checksum error\n", + boardp->id); break; case ASC_WARN_IRQ_MODIFIED: - ASC_DBG(0, "AscInitGetConfig: IRQ modified\n"); + ASC_PRINT1( +"AscInitGetConfig: Board %d: IRQ modified\n", + boardp->id); break; case ASC_WARN_CMD_QNG_CONFLICT: - ASC_DBG(0, - "AscInitGetConfig: Tag queuing enabled w/o disconnects\n"); + ASC_PRINT1( +"AscInitGetConfig: Board %d: tag queuing enabled w/o disconnects\n", + boardp->id); break; default: - ASC_DBG1(0, "AscInitGetConfig: Unknown warning: %x\n", ret); + ASC_PRINT2( +"AscInitGetConfig: Board %d: unknown warning: %x\n", + boardp->id, ret); break; } - if (boardp->err_code != 0) { - ASC_DBG2(0, - "AscInitGetConfig: error: init_state %x, err_code %x\n", - boardp->init_state, boardp->err_code); + if (asc_dvc_varp->err_code != 0) { + ASC_PRINT3( +"AscInitGetConfig: Board %d error: init_state %x, err_code %x\n", + boardp->id, asc_dvc_varp->init_state, + asc_dvc_varp->err_code); +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + kfree(boardp->prtbuf); +#endif /* version >= v1.3.0 */ scsi_unregister(shp); asc_board_count--; continue; } /* + * Set the adapter's target id bit in the init_tidmask field. + */ + boardp->init_tidmask |= + ASC_TIX_TO_TARGET_ID(asc_dvc_varp->cfg->chip_scsi_id); + + /* + * Save EEPROM settings for the board. + */ + boardp->eep_config.init_sdtr = asc_dvc_varp->init_sdtr; + boardp->eep_config.disc_enable = asc_dvc_varp->cfg->disc_enable; + boardp->eep_config.use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled; + boardp->eep_config.isa_dma_speed = asc_dvc_varp->cfg->isa_dma_speed; + boardp->eep_config.start_motor = asc_dvc_varp->start_motor; + boardp->eep_config.cntl = asc_dvc_varp->dvc_cntl; + boardp->eep_config.no_scam = asc_dvc_varp->no_scam; + boardp->eep_config.max_total_qng = asc_dvc_varp->max_total_qng; + boardp->eep_config.chip_scsi_id = asc_dvc_varp->cfg->chip_scsi_id; + /* 'max_tag_qng' is set to the same value for every device. */ + boardp->eep_config.max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0]; + + /* * Modify board configuration. */ - boardp->isr_callback = (Ptr2Func) asc_isr_callback; - boardp->exe_callback = (Ptr2Func) NULL; + asc_dvc_varp->isr_callback = (Ptr2Func) asc_isr_callback; + asc_dvc_varp->exe_callback = (Ptr2Func) NULL; ASC_DBG(2, "advansys_detect: AscInitSetConfig()\n"); - switch (ret = AscInitSetConfig(boardp)) { + switch (ret = AscInitSetConfig(asc_dvc_varp)) { case 0: /* No error. */ break; case ASC_WARN_IO_PORT_ROTATE: - ASC_DBG(0, "AscInitSetConfig: I/O port address modified\n"); + ASC_PRINT1( +"AscInitSetConfig: Board %d: I/O port address modified\n", + boardp->id); + break; + case ASC_WARN_AUTO_CONFIG: + ASC_PRINT1( +"AscInitSetConfig: Board %d: I/O port increment switch enabled\n", + boardp->id); break; case ASC_WARN_EEPROM_CHKSUM: - ASC_DBG(0, "AscInitSetConfig: EEPROM checksum error\n"); + ASC_PRINT1( +"AscInitSetConfig: Board %d: EEPROM checksum error\n", + boardp->id); break; case ASC_WARN_IRQ_MODIFIED: - ASC_DBG(0, "AscInitSetConfig: IRQ modified\n"); + ASC_PRINT1( +"AscInitSetConfig: Board %d: IRQ modified\n", + boardp->id); break; case ASC_WARN_CMD_QNG_CONFLICT: - ASC_DBG(0, "AscInitSetConfig: Tag queuing w/o disconnects\n"); + ASC_PRINT1( +"AscInitSetConfig: Board %d: tag queuing w/o disconnects\n", + boardp->id); break; default: - ASC_DBG1(0, "AscInitSetConfig: Unknown warning: %x\n", ret); + ASC_PRINT2( +"AscInitSetConfig: Board %d: unknown warning: %x\n", + boardp->id, ret); break; } - if (boardp->err_code != 0) { - ASC_DBG2(0, - "AscInitSetConfig: error: init_state %x, err_code %x\n", - boardp->init_state, boardp->err_code); + if (asc_dvc_varp->err_code != 0) { + ASC_PRINT3( +"AscInitSetConfig: Board %d error: init_state %x, err_code %x\n", + boardp->id, asc_dvc_varp->init_state, + asc_dvc_varp->err_code); +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + kfree(boardp->prtbuf); +#endif /* version >= v1.3.0 */ scsi_unregister(shp); asc_board_count--; continue; @@ -3030,33 +3164,21 @@ */ /* AscInitSetConfig() will set the IRQ for non-PCI boards. */ - if (boardp->bus_type != ASC_IS_PCI) { - shp->irq = boardp->irq_no; + if (asc_dvc_varp->bus_type != ASC_IS_PCI) { + shp->irq = asc_dvc_varp->irq_no; } - shp->io_port = boardp->iop_base; + shp->io_port = asc_dvc_varp->iop_base; shp->n_io_port = ASC_IOADR_GAP; - shp->this_id = boardp->cfg->chip_scsi_id; + shp->this_id = asc_dvc_varp->cfg->chip_scsi_id; /* Maximum number of queues this adapter can handle. */ - shp->can_queue = boardp->max_total_qng; + shp->can_queue = asc_dvc_varp->max_total_qng; +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89) /* - * XXX - Command queuing limits are maintained per target - * by AdvanSys adapters. Set 'cmd_per_lun' to the minimum - * value of the all the target settings for the adapter. - * - * For now set 'cmd_per_lun' to 'max_total_qng'. This - * value should be adjusted every time a new device is - * found in asc_init_dev(). - * - * XXX - memory allocation is done by the mid-level scsi - * driver based on 'cmd_per_lun'. If 'sg_tablesize' is too large - * allocation failures can occur in scsi_register_host(). - * A 'Scsi_Cmnd' structure is pre-allocated for each command - * also DMA memory is reserved. Set it artificially low for now. - * - * shp->cmd_per_lun = boardp->max_total_qng; + * Set a conservative 'cmd_per_lun' value to prevent memory + * allocation failures. */ #ifdef MODULE shp->cmd_per_lun = 1; @@ -3064,12 +3186,22 @@ shp->cmd_per_lun = 4; #endif /* MODULE */ ASC_DBG1(1, "advansys_detect: cmd_per_lun: %d\n", shp->cmd_per_lun); +#else /* version >= v1.3.89 */ + /* + * Use the host 'select_queue_depths' function to determine + * the number of commands to queue per device. + */ + shp->select_queue_depths = advansys_select_queue_depths; + + shp->cmd_per_lun = 0; /* 'cmd_per_lun' is no longer used. */ +#endif /* version >= v1.3.89 */ + - /* Maximum number of scatter-gather elements adapter can handle. */ /* - * XXX - memory allocation is done by the mid-level scsi - * driver based on sg_tablesize. If 'sg_tablesize' is too large - * allocation failures can occur in scsi_register_host(). + * Maximum number of scatter-gather elements adapter can handle. + * + * Set a conservative 'sg_tablesize' value to prevent memory + * allocation failures. */ #ifdef MODULE shp->sg_tablesize = 8; @@ -3081,8 +3213,8 @@ /* BIOS start address. */ shp->base = (char *) ((ulong) AscGetChipBiosAddress( - boardp->iop_base, - boardp->bus_type)); + asc_dvc_varp->iop_base, + asc_dvc_varp->bus_type)); /* * Register Board Resources - I/O Port, DMA, IRQ @@ -3093,14 +3225,18 @@ request_region(shp->io_port, shp->n_io_port, "advansys"); /* Register DMA channel for ISA bus. */ - if ((boardp->bus_type & ASC_IS_ISA) == 0) { + if ((asc_dvc_varp->bus_type & ASC_IS_ISA) == 0) { shp->dma_channel = NO_ISA_DMA; } else { - shp->dma_channel = boardp->cfg->isa_dma_channel; + shp->dma_channel = asc_dvc_varp->cfg->isa_dma_channel; if ((ret = request_dma(shp->dma_channel, "advansys")) != 0) { - ASC_DBG2(0, "advansys_detect: request_dma() %d failed %d\n", - shp->dma_channel, ret); + ASC_PRINT3( +"advansys_detect: Board %d: request_dma() %d failed %d\n", + boardp->id, shp->dma_channel, ret); release_region(shp->io_port, shp->n_io_port); +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + kfree(boardp->prtbuf); +#endif /* version >= v1.3.0 */ scsi_unregister(shp); asc_board_count--; continue; @@ -3110,18 +3246,24 @@ /* Register IRQ Number. */ ASC_DBG1(2, "advansys_detect: request_irq() %d\n", shp->irq); -#ifdef LINUX_1_2 +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70) if ((ret = request_irq(shp->irq, advansys_interrupt, - SA_INTERRUPT, "advansys")) != 0) { -#else /* LINUX_1_3 */ + SA_INTERRUPT, "advansys")) != 0) { +#else /* version >= v1.3.70 */ if ((ret = request_irq(shp->irq, advansys_interrupt, - SA_INTERRUPT, "advansys", NULL)) != 0) { -#endif /* LINUX_1_3 */ - ASC_DBG1(0, "advansys_detect: request_irq() failed %d\n", ret); + SA_INTERRUPT | (share_irq == TRUE ? SA_SHIRQ : 0), + "advansys", boardp)) != 0) { +#endif /* version >= v1.3.70 */ + ASC_PRINT2( +"advansys_detect: Board %d: request_irq() failed %d\n", + boardp->id, ret); release_region(shp->io_port, shp->n_io_port); if (shp->dma_channel != NO_ISA_DMA) { free_dma(shp->dma_channel); } +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + kfree(boardp->prtbuf); +#endif /* version >= v1.3.0 */ scsi_unregister(shp); asc_board_count--; continue; @@ -3131,19 +3273,23 @@ * Initialize board RISC chip and enable interrupts. */ ASC_DBG(2, "advansys_detect: AscInitAsc1000Driver()\n"); - if (AscInitAsc1000Driver(boardp)) { - ASC_DBG2(0, - "AscInitAsc1000Driver: error: init_state %x, err_code %x\n", - boardp->init_state, boardp->err_code); + if (AscInitAsc1000Driver(asc_dvc_varp)) { + ASC_PRINT3( +"AscInitAsc1000Driver: Board %d error: init_state %x, err_code %x\n", + boardp->id, asc_dvc_varp->init_state, + asc_dvc_varp->err_code); release_region(shp->io_port, shp->n_io_port); if (shp->dma_channel != NO_ISA_DMA) { free_dma(shp->dma_channel); } -#ifdef LINUX_1_2 +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + kfree(boardp->prtbuf); +#endif /* version >= v1.3.0 */ +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70) free_irq(shp->irq); -#else /* LINUX_1_3 */ - free_irq(shp->irq, NULL); -#endif /* LINUX_1_3 */ +#else /* version >= v1.3.70 */ + free_irq(shp->irq, boardp); +#endif /* version >= v1.3.70 */ scsi_unregister(shp); asc_board_count--; continue; @@ -3151,7 +3297,6 @@ ASC_DBG_PRT_SCSI_HOST(2, shp); } } - ASC_DBG1(1, "advansys_detect: done: asc_board_count %d\n", asc_board_count); return asc_board_count; } @@ -3164,17 +3309,24 @@ int advansys_release(struct Scsi_Host *shp) { + struct asc_board *boardp; + ASC_DBG(1, "advansys_release: begin\n"); -#ifdef LINUX_1_2 + boardp = ASC_BOARDP(shp); +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70) free_irq(shp->irq); -#else /* LINUX_1_3 */ - free_irq(shp->irq, NULL); -#endif /* LINUX_1_3 */ +#else /* version >= v1.3.70 */ + free_irq(shp->irq, boardp); +#endif /* version >= v1.3.70 */ if (shp->dma_channel != NO_ISA_DMA) { ASC_DBG(1, "advansys_release: free_dma()\n"); free_dma(shp->dma_channel); } release_region(shp->io_port, shp->n_io_port); +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) + ASC_ASSERT(boardp->prtbuf != NULL); + kfree(boardp->prtbuf); +#endif /* version >= v1.3.0 */ scsi_unregister(shp); ASC_DBG(1, "advansys_release: end\n"); return 0; @@ -3185,46 +3337,50 @@ * * Return suitable for printing on the console with the argument * adapter's configuration information. + * + * Note: The information line should not exceed ASC_INFO_SIZE bytes, + * otherwise the static 'info' array will be overrun. */ const char * advansys_info(struct Scsi_Host *shp) { - static char info[128]; - ASC_DVC_VAR *boardp; - char *busname; + static char info[ASC_INFO_SIZE]; + struct asc_board *boardp; + ASC_DVC_VAR *asc_dvc_varp; + char *busname; - boardp = &ASC_BOARD(shp)->board; + boardp = ASC_BOARDP(shp); + asc_dvc_varp = &boardp->asc_dvc_var; ASC_DBG(1, "advansys_info: begin\n"); - if (boardp->bus_type & ASC_IS_ISA) { + if (asc_dvc_varp->bus_type & ASC_IS_ISA) { sprintf(info, "AdvanSys SCSI %s: ISA (%u CDB): BIOS %X, IO %X-%X, IRQ %u, DMA %u", - ASC_VERSION, ASC_BOARD(shp)->board.max_total_qng, + ASC_VERSION, boardp->asc_dvc_var.max_total_qng, (unsigned) shp->base, shp->io_port, shp->io_port + (shp->n_io_port - 1), shp->irq, shp->dma_channel); } else { - switch (boardp->bus_type) { - case ASC_IS_EISA: - busname = "EISA"; - break; - case ASC_IS_VL: + if (asc_dvc_varp->bus_type & ASC_IS_VL) { busname = "VL"; - break; - case ASC_IS_PCI: + } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) { + busname = "EISA"; + } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) { busname = "PCI"; - break; - default: + } else { busname = "?"; - ASC_DBG1(0, "advansys_info: unknown bus type %d\n", - boardp->bus_type); - break; + ASC_PRINT2( +"advansys_info: Board %d: unknown bus type %d\n", + boardp->id, asc_dvc_varp->bus_type); } /* No DMA channel for non-ISA busses. */ sprintf(info, "AdvanSys SCSI %s: %s (%u CDB): BIOS %X, IO %X-%X, IRQ %u", - ASC_VERSION, busname, ASC_BOARD(shp)->board.max_total_qng, + ASC_VERSION, busname, boardp->asc_dvc_var.max_total_qng, (unsigned) shp->base, shp->io_port, shp->io_port + (shp->n_io_port - 1), shp->irq); } +#ifdef ADVANSYS_DEBUG + ASC_ASSERT(strlen(info) < ASC_INFO_SIZE); +#endif /* ADVANSYS_DEBUG */ ASC_DBG(1, "advansys_info: end\n"); return info; } @@ -3241,7 +3397,7 @@ advansys_command(Scsi_Cmnd *scp) { ASC_DBG1(1, "advansys_command: scp %x\n", (unsigned) scp); - ASC_STATS(command); + ASC_STATS(scp->host, command); scp->SCp.Status = 0; /* Set to a known state */ advansys_queuecommand(scp, advansys_command_done); while (scp->SCp.Status == 0) { @@ -3261,26 +3417,13 @@ advansys_queuecommand(Scsi_Cmnd *scp, void (*done)(Scsi_Cmnd *)) { struct Scsi_Host *shp; + struct asc_board *boardp; int flags = 0; int interrupts_disabled; - ASC_STATS(queuecommand); shp = scp->host; - -#ifdef LINUX_1_2 - /* - * For LINUX_1_3, if statistics are enabled they can be accessed - * by reading /proc/scsi/advansys/[0-(ASC_NUM_BOARD_SUPPORTED-1)]. - */ -#ifdef ADVANSYS_STATS_1_2_PRINT - /* Display statistics every 10000 commands. */ - if ((asc_stats.queuecommand % 10000) == 0) { - printk("\n"); - (void) asc_prt_stats(NULL, 0); - printk("\n"); - } -#endif /* ADVANSYS_STATS_1_2_PRINT */ -#endif /* LINUX_1_2 */ + boardp = ASC_BOARDP(shp); + ASC_STATS(shp, queuecommand); /* * If there are any pending commands for this board before trying @@ -3289,17 +3432,16 @@ * The typical case will be no pending commands and interrupts * not disabled. */ - if (ASC_BOARD(shp)->pending_tidmask == 0) { + if (boardp->pending.tidmask == 0) { interrupts_disabled = ASC_FALSE; } else { - ASC_STATS(cmd_disable); /* Disable interrupts */ interrupts_disabled = ASC_TRUE; save_flags(flags); cli(); - ASC_DBG1(1, "advansys_queuecommand: asc_execute_pending() %x\n", - ASC_BOARD(shp)->pending_tidmask); - asc_execute_pending(shp); + ASC_DBG1(1, "advansys_queuecommand: asc_execute_queue() %x\n", + boardp->pending.tidmask); + asc_execute_queue(&boardp->pending); } /* @@ -3313,7 +3455,7 @@ cli(); interrupts_disabled = ASC_TRUE; } - asc_enqueue(shp, scp, scp->target, ASC_BACK); + asc_enqueue(&boardp->pending, scp, ASC_BACK); } if (interrupts_disabled == ASC_TRUE) { @@ -3326,50 +3468,87 @@ /* * advansys_abort() * - * Abort the specified command and reset the device - * associated with the command 'scp'. + * Abort the command specified by 'scp'. */ int advansys_abort(Scsi_Cmnd *scp) { - ASC_DVC_VAR *boardp; - int flags; - int ret; + struct asc_board *boardp; + ASC_DVC_VAR *asc_dvc_varp; + int flags; + int abort; + int ret; ASC_DBG1(1, "advansys_abort: scp %x\n", (unsigned) scp); + ASC_STATS(scp->host, abort); + + /* Save current flags and disable interrupts. */ save_flags(flags); cli(); - ASC_STATS(abort); + +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) + if (scp->serial_number != scp->serial_number_at_timeout) { + ret = SCSI_ABORT_NOT_RUNNING; + } else +#endif /* version >= v1.3.89 */ if (scp->host == NULL) { scp->result = HOST_BYTE(DID_ERROR); ret = SCSI_ABORT_ERROR; - } else if (asc_rmqueue(scp->host, scp, scp->target) == ASC_TRUE) { - scp->result = HOST_BYTE(DID_ABORT); - ret = SCSI_ABORT_SUCCESS; - (void) AscResetDevice(&ASC_BOARD(scp->host)->board, scp->target); } else { - /* Must enable interrupts for AscAbortSRB() */ - sti(); - boardp = &ASC_BOARD(scp->host)->board; - scp->result = HOST_BYTE(DID_ABORT); - switch (AscAbortSRB(boardp, (ulong) scp)) { - case ASC_TRUE: - /* asc_isr_callback() will be called */ - ASC_DBG(1, "advansys_abort: AscAbortSRB() TRUE\n"); - ret = SCSI_ABORT_PENDING; - break; - case ASC_FALSE: - /* Request has apparently already completed. */ - ASC_DBG(1, "advansys_abort: AscAbortSRB() FALSE\n"); + boardp = ASC_BOARDP(scp->host); + if (asc_rmqueue(&boardp->pending, scp) == ASC_TRUE) { + /* + * If asc_rmqueue() found the command on the pending + * queue, it had not been sent to the Asc Library. + * After the queue is removed, no other handling is required. + */ + scp->result = HOST_BYTE(DID_ABORT); + ret = SCSI_ABORT_SUCCESS; + } else if (asc_isqueued(&boardp->active, scp) == ASC_TRUE) { + /* + * If asc_isqueued() found the command on the active + * queue, it has been sent to the Asc Library. The + * command should be returned through the interrupt + * handler after calling AscAbortSRB(). + */ + asc_dvc_varp = &boardp->asc_dvc_var; + scp->result = HOST_BYTE(DID_ABORT); + /* Must enable interrupts for AscAbortSRB() */ + sti(); + switch (abort = AscAbortSRB(asc_dvc_varp, (ulong) scp)) { + case ASC_TRUE: + /* asc_isr_callback() will be called */ + ASC_DBG(1, "advansys_abort: AscAbortSRB() TRUE\n"); + ret = SCSI_ABORT_PENDING; + break; + case ASC_FALSE: + /* Request has apparently already completed. */ + ASC_DBG(1, "advansys_abort: AscAbortSRB() FALSE\n"); + ret = SCSI_ABORT_NOT_RUNNING; + break; + case ASC_ERROR: + default: + ASC_DBG(1, "advansys_abort: AscAbortSRB() ERROR\n"); + ret = SCSI_ABORT_ERROR; + break; + } + cli(); + /* + * If the abort failed, remove the request from the + * active list and complete it. + */ + if (abort != ASC_TRUE) { + if (asc_rmqueue(&boardp->active, scp) == ASC_TRUE) { + scp->result = HOST_BYTE(DID_ABORT); + scp->scsi_done(scp); + } + } + } else { + /* + * The command was not found on the active or pending queues. + */ ret = SCSI_ABORT_NOT_RUNNING; - break; - case ASC_ERROR: - default: - ASC_DBG(1, "advansys_abort: AscAbortSRB() ERROR\n"); - ret = SCSI_ABORT_ERROR; - break; } - (void) AscResetDevice(boardp, scp->target); } restore_flags(flags); ASC_DBG1(1, "advansys_abort: ret %d\n", ret); @@ -3379,82 +3558,169 @@ /* * advansys_reset() * - * Reset all devices and the SCSI bus for the board - * associated with 'scp'. + * Reset the device associated with the command 'scp'. */ int +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89) advansys_reset(Scsi_Cmnd *scp) +#else /* version >= v1.3.89 */ +advansys_reset(Scsi_Cmnd *scp, unsigned int reset_flags) +#endif /* version >= v1.3.89 */ { - ASC_DVC_VAR *boardp; - int flags; - Scsi_Cmnd *tscp; - int i; - int ret; + struct asc_board *boardp; + ASC_DVC_VAR *asc_dvc_varp; + int flags; + Scsi_Cmnd *tscp; +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) + int scp_found = ASC_FALSE; +#endif /* version >= v1.3.89 */ + int i; + int ret; ASC_DBG1(1, "advansys_reset: %x\n", (unsigned) scp); + ASC_STATS(scp->host, reset); + + /* Save current flags and disable interrupts. */ save_flags(flags); cli(); - ASC_STATS(reset); + +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) + if (scp->serial_number != scp->serial_number_at_timeout) { + ret = SCSI_RESET_NOT_RUNNING; + } else +#endif /* version >= v1.3.89 */ if (scp->host == NULL) { scp->result = HOST_BYTE(DID_ERROR); ret = SCSI_RESET_ERROR; } else { - /* Remove any pending commands, set DID_RESET, and done them. */ - for (i = 0; i < ASC_MAX_TID; i++) { - while ((tscp = asc_dequeue(scp->host, i)) != NULL) { - tscp->result = HOST_BYTE(DID_RESET); - tscp->scsi_done(tscp); - } + boardp = ASC_BOARDP(scp->host); + +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) + /* + * If the request is on the target pending or active queue, + * note that it was found. + */ + if ((asc_isqueued(&boardp->pending, scp) == ASC_TRUE) || + (asc_isqueued(&boardp->active, scp) == ASC_TRUE)) { + scp_found = ASC_TRUE; } +#endif /* version >= v1.3.89 */ + /* - * XXX - Host drivers should not modify the timeout field. - * Allow the SCSI bus reset more time to complete. + * If the suggest reset bus flags are set, reset the bus. + * Otherwise only reset the device. */ - scp->timeout += 2000; /* Add 5 seconds to the request timeout. */ + asc_dvc_varp = &boardp->asc_dvc_var; +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) + if (reset_flags & + (SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET)) { +#endif /* version >= v1.3.89 */ - /* Must enable interrupts for AscResetSB() */ - sti(); - boardp = &ASC_BOARD(scp->host)->board; - scp->result = HOST_BYTE(DID_RESET); - switch (AscResetSB(boardp)) { - case ASC_TRUE: - ASC_DBG(1, "advansys_reset: AscResetSB() TRUE\n"); - ret = SCSI_RESET_SUCCESS; - break; - case ASC_ERROR: - default: - ASC_DBG(1, "advansys_reset: AscResetSB() ERROR\n"); - ret = SCSI_RESET_ERROR; - break; - } - } - restore_flags(flags); - ASC_DBG1(1, "advansys_reset: ret %d", ret); - return ret; -} + /* + * Done all pending requests for all targets with DID_RESET. + */ + for (i = 0; i <= ASC_MAX_TID; i++) { + while ((tscp = asc_dequeue(&boardp->pending, i)) != NULL) { + tscp->result = HOST_BYTE(DID_RESET); + tscp->scsi_done(tscp); + } + } -/* - * advansys_biosparam() - * - * Translate disk drive geometry if the "BIOS greater than 1 GB" - * support is enabled for a drive. - * - * ip (information pointer) is an int array with the following definition: - * ip[0]: heads - * ip[1]: sectors - * ip[2]: cylinders + /* + * Reset the target's SCSI bus. + */ + sti(); /* Enable interrupts for AscResetSB(). */ + switch (AscResetSB(asc_dvc_varp)) { + case ASC_TRUE: + ASC_DBG(1, "advansys_reset: AscResetSB() TRUE\n"); + ret = SCSI_RESET_SUCCESS; + break; + case ASC_ERROR: + default: + ASC_DBG(1, "advansys_reset: AscResetSB() ERROR\n"); + ret = SCSI_RESET_ERROR; + break; + } + cli(); + + /* + * Done all active requests for all targets with DID_RESET. + */ + for (i = 0; i <= ASC_MAX_TID; i++) { + while ((tscp = asc_dequeue(&boardp->active, i)) != NULL) { + tscp->result = HOST_BYTE(DID_RESET); + tscp->scsi_done(tscp); + } + } +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) + } else { + /* + * Done all pending requests for the target with DID_RESET. + */ + while ((tscp = asc_dequeue(&boardp->pending, scp->target)) + != NULL) { + tscp->result = HOST_BYTE(DID_RESET); + tscp->scsi_done(tscp); + } + + sti(); /* Enabled interrupts for AscResetDevice(). */ + ASC_DBG(1, "advansys_reset: AscResetDevice()\n"); + (void) AscResetDevice(asc_dvc_varp, scp->target); + cli(); + + /* + * Done all active requests for the target with DID_RESET. + */ + while ((tscp = asc_dequeue(&boardp->active, scp->target)) + != NULL) { + tscp->result = HOST_BYTE(DID_RESET); + tscp->scsi_done(tscp); + } + } +#endif /* version >= v1.3.89 */ + +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) + /* + * If the command was not on the active or pending request + * queues and the SCSI_RESET_SYNCHRONOUS flag is set, then + * done the command now. If the command had been on the + * active or pending request queues it would have already + * been completed. + */ + if (scp_found == ASC_FALSE && (reset_flags & SCSI_RESET_SYNCHRONOUS)) { + scp->result = HOST_BYTE(DID_RESET); + scp->scsi_done(tscp); + } +#endif /* version >= v1.3.89 */ + ret = SCSI_RESET_SUCCESS; + } + restore_flags(flags); + ASC_DBG1(1, "advansys_reset: ret %d", ret); + return ret; +} + +/* + * advansys_biosparam() + * + * Translate disk drive geometry if the "BIOS greater than 1 GB" + * support is enabled for a drive. + * + * ip (information pointer) is an int array with the following definition: + * ip[0]: heads + * ip[1]: sectors + * ip[2]: cylinders */ int -#ifdef LINUX_1_2 +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) advansys_biosparam(Disk *dp, int dep, int ip[]) -#else /* LINUX_1_3 */ +#else /* version >= v1.3.0 */ advansys_biosparam(Disk *dp, kdev_t dep, int ip[]) -#endif /* LINUX_1_3 */ +#endif /* version >= v1.3.0 */ { ASC_DBG(1, "advansys_biosparam: begin\n"); - ASC_STATS(biosparam); - if ((ASC_BOARD(dp->device->host)->board.dvc_cntl & ASC_CNTL_BIOS_GT_1GB) && - dp->capacity > 0x200000) { + ASC_STATS(dp->device->host, biosparam); + if ((ASC_BOARDP(dp->device->host)->asc_dvc_var.dvc_cntl & + ASC_CNTL_BIOS_GT_1GB) && dp->capacity > 0x200000) { ip[0] = 255; ip[1] = 63; } else { @@ -3556,49 +3822,21 @@ * --- Miscellaneous Driver Functions */ -#ifdef LINUX_1_3 -/* - * asc_proc_copy() - * - * Copy proc information to a read buffer considering the current read - * offset in the file and the remaining space in the read buffer. - */ -STATIC int -asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen, - char *cp, int cplen) -{ - int cnt = 0; - - ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n", - (unsigned) offset, (unsigned) advoffset, cplen); - if (offset <= advoffset) { - /* Read offset below current offset, copy everything. */ - cnt = min(cplen, leftlen); - ASC_DBG3(2, "asc_proc_copy: curbuf %x, cp %x, cnt %d\n", - (unsigned) curbuf, (unsigned) cp, cnt); - memcpy(curbuf, cp, cnt); - } else if (offset < advoffset + cplen) { - /* Read offset within current range, partial copy. */ - cnt = (advoffset + cplen) - offset; - cp = (cp + cplen) - cnt; - cnt = min(cnt, leftlen); - ASC_DBG3(2, "asc_proc_copy: curbuf %x, cp %x, cnt %d\n", - (unsigned) curbuf, (unsigned) cp, cnt); - memcpy(curbuf, cp, cnt); - } - return cnt; -} -#endif /* LINUX_1_3 */ - /* * First-level interrupt handler. + * + * For versions > v1.3.70, 'dev_id' is a pointer to the interrupting + * adapter's struct asc_board. Because all boards are currently checked + * for interrupts on each interrupt, 'dev_id' is not referenced. 'dev_id' + * could be used to identify an interrupt passed to the AdvanSys driver + * but actually for a device sharing an interrupt with an AdvanSys adapter. */ STATIC void -#ifdef LINUX_1_2 +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70) advansys_interrupt(int irq, struct pt_regs *regs) -#else /* LINUX_1_3 */ +#else /* version >= v1.3.70 */ advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs) -#endif /* LINUX_1_3 */ +#endif /* version >= v1.3.70 */ { int i; int flags; @@ -3610,18 +3848,18 @@ cli(); ASC_DBG(1, "advansys_interrupt: begin\n"); - ASC_STATS(interrupt); /* * Check for interrupts on all boards. * AscISR() will call asc_isr_callback(). */ for (i = 0; i < asc_board_count; i++) { + ASC_STATS(asc_host[i], check_interrupt); while (AscIsIntPending(asc_host[i]->io_port)) { + ASC_STATS(asc_host[i], interrupt); ASC_DBG(1, "advansys_interrupt: before AscISR()\n"); - AscISR(&ASC_BOARD(asc_host[i])->board); + AscISR(&ASC_BOARDP(asc_host[i])->asc_dvc_var); } } - ASC_DBG(1, "advansys_interrupt: end\n"); /* * While interrupts are still disabled save the list of requests that @@ -3641,9 +3879,33 @@ scp = tscp; } + ASC_DBG(1, "advansys_interrupt: end\n"); return; } +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89) +/* + * Set the number of commands to queue per device for the + * specified host adapter. + */ +STATIC void +advansys_select_queue_depths(struct Scsi_Host *shp, Scsi_Device *devicelist) +{ + Scsi_Device *device; + struct asc_board *boardp; + + boardp = ASC_BOARDP(shp); + for (device = devicelist; device != NULL; device = device->next) { + if (device->host != shp) { + continue; + } + device->queue_depth = boardp->asc_dvc_var.max_dvc_qng[device->id]; + ASC_DBG3(1, "advansys_select_queue_depths: shp %x, id %d, depth %d\n", + (unsigned) shp, device->id, device->queue_depth); + } +} +#endif /* version >= v1.3.89 */ + /* * Function used only with polled I/O requests that are initiated by * advansys_command(). @@ -3697,28 +3959,30 @@ STATIC int asc_execute_scsi_cmnd(Scsi_Cmnd *scp) { - ASC_DVC_VAR *boardp; - ASC_SCSI_Q scsiq; - ASC_SG_HEAD sghead; - int ret; + struct asc_board *boardp; + ASC_DVC_VAR *asc_dvc_varp; + ASC_SCSI_Q scsiq; + ASC_SG_HEAD sghead; + int flags; + int ret; ASC_DBG2(1, "asc_execute_scsi_cmnd: scp %x, done %x\n", (unsigned) scp, (unsigned) scp->scsi_done); - boardp = &ASC_BOARD(scp->host)->board; + boardp = ASC_BOARDP(scp->host); + asc_dvc_varp = &boardp->asc_dvc_var; /* * If this is the first command, then initialize the device. If * no device is found set 'DID_BAD_TARGET' and return. */ - if ((ASC_BOARD(scp->host)->init_tidmask & - ASC_TIX_TO_TARGET_ID(scp->target)) == 0) { - if (asc_init_dev(boardp, scp) == ASC_FALSE) { + if ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(scp->target)) == 0) { + if (asc_init_dev(asc_dvc_varp, scp) == ASC_FALSE) { scp->result = HOST_BYTE(DID_BAD_TARGET); scp->scsi_done(scp); return ASC_ERROR; } - ASC_BOARD(scp->host)->init_tidmask |= ASC_TIX_TO_TARGET_ID(scp->target); + boardp->init_tidmask |= ASC_TIX_TO_TARGET_ID(scp->target); } memset(&scsiq, 0, sizeof(ASC_SCSI_Q)); @@ -3748,11 +4012,12 @@ /* * CDB request of single contiguous buffer. */ - ASC_STATS(cont_cnt); + ASC_STATS(scp->host, cont_cnt); /* request_buffer is already a real address. */ scsiq.q1.data_addr = (ulong) scp->request_buffer; scsiq.q1.data_cnt = scp->request_bufflen; - ASC_STATS_ADD(cont_xfer, (scp->request_bufflen + 511) >> 9); + ASC_STATS_ADD(scp->host, cont_xfer, + ASC_CEILING(scp->request_bufflen, 512)); scsiq.q1.sg_queue_cnt = 0; scsiq.sg_head = NULL; } else { @@ -3763,14 +4028,14 @@ struct scatterlist *slp; if (scp->use_sg > ASC_MAX_SG_LIST) { - ASC_DBG2(0, "asc_execute_scsi_cmnd: use_sg %d > %d\n", - scp->use_sg, ASC_MAX_SG_LIST); + ASC_PRINT3("asc_execute_scsi_cmnd: Board %d: use_sg %d > %d\n", + boardp->id, scp->use_sg, ASC_MAX_SG_LIST); scp->result = HOST_BYTE(DID_ERROR); scp->scsi_done(scp); return ASC_ERROR; } - ASC_STATS(sg_cnt); + ASC_STATS(scp->host, sg_cnt); /* * Allocate a ASC_SG_HEAD structure and set the ASC_SCSI_Q @@ -3783,7 +4048,7 @@ scsiq.q1.data_cnt = 0; scsiq.q1.data_addr = 0; sghead.entry_cnt = scsiq.q1.sg_queue_cnt = scp->use_sg; - ASC_STATS_ADD(sg_elem, sghead.entry_cnt); + ASC_STATS_ADD(scp->host, sg_elem, sghead.entry_cnt); /* * Convert scatter-gather list into ASC_SG_HEAD list. @@ -3792,29 +4057,48 @@ for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) { sghead.sg_list[sgcnt].addr = (ulong) slp->address; sghead.sg_list[sgcnt].bytes = slp->length; - ASC_STATS_ADD(sg_xfer, (slp->length + 511) >> 9); + ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512)); } } ASC_DBG_PRT_SCSI_Q(2, &scsiq); ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len); - switch (ret = AscExeScsiQueue(boardp, &scsiq)) { + /* + * Disable interrupts to issue the command and add the + * command to the active queue if it is started. + */ + save_flags(flags); + cli(); + + switch (ret = AscExeScsiQueue(asc_dvc_varp, &scsiq)) { case ASC_NOERROR: - ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue() ASC_NOERROR\n"); + asc_enqueue(&boardp->active, scp, ASC_BACK); + ASC_STATS(scp->host, asc_noerror); + ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n"); break; case ASC_BUSY: /* Caller must enqueue request and retry later. */ + ASC_STATS(scp->host, asc_busy); break; case ASC_ERROR: - ASC_DBG1(0, - "asc_execute_scsi_cmnd: AscExeScsiQueue() ASC_ERROR err_code %x\n", - boardp->err_code); - ASC_STATS(error); + ASC_PRINT2( +"asc_execute_scsi_cmnd: Board %d: AscExeScsiQueue() ASC_ERROR, err_code %x\n", + boardp->id, asc_dvc_varp->err_code); + ASC_STATS(scp->host, asc_error); + scp->result = HOST_BYTE(DID_ERROR); + scp->scsi_done(scp); + break; + default: + ASC_PRINT2( +"asc_execute_scsi_cmnd: Board %d: AscExeScsiQueue() unknown, err_code %x\n", + boardp->id, asc_dvc_varp->err_code); + ASC_STATS(scp->host, asc_unknown); scp->result = HOST_BYTE(DID_ERROR); scp->scsi_done(scp); break; } + restore_flags(flags); ASC_DBG(1, "asc_execute_scsi_cmnd: end\n"); return ret; @@ -3824,17 +4108,16 @@ * asc_isr_callback() - Second Level Interrupt Handler called by AscISR(). */ void -asc_isr_callback(ASC_DVC_VAR *boardp, ASC_QDONE_INFO *qdonep) +asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep) { + struct asc_board *boardp; Scsi_Cmnd *scp; struct Scsi_Host *shp; - int flags; Scsi_Cmnd **scpp; ASC_ASSERT(interrupts_enabled() == ASC_FALSE); - ASC_DBG2(1, "asc_isr_callback: boardp %x, qdonep %x\n", - (unsigned) boardp, (unsigned) qdonep); - ASC_STATS(callback); + ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp %x, qdonep %x\n", + (unsigned) asc_dvc_varp, (unsigned) qdonep); ASC_DBG_PRT_QDONE_INFO(2, qdonep); /* @@ -3847,8 +4130,16 @@ shp = scp->host; ASC_ASSERT(shp); + ASC_STATS(shp, callback); ASC_DBG1(1, "asc_isr_callback: shp %x\n", (unsigned) shp); + boardp = ASC_BOARDP(shp); + if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) { + ASC_PRINT2( +"asc_isr_callback: Board %d: scp %x not on active queue\n", + boardp->id, (unsigned) scp); + } + /* * 'qdonep' contains the command's ending status. */ @@ -3875,12 +4166,14 @@ ASC_DBG_PRT_SENSE(2, scp->sense_buffer, sizeof(scp->sense_buffer)); /* - * Note: The status_byte() macro used by target drivers + * Note: The 'status_byte()' macro used by target drivers * defined in scsi.h shifts the status byte returned by * host drivers right by 1 bit. This is why target drivers - * also use left shifted status byte definitions. For instance - * target drivers use CHECK_CONDITION, defined to 0x1, instead - * of the SCSI defined check condition value of 0x2. + * also use right shifted status byte definitions. For + * instance target drivers use CHECK_CONDITION, defined to + * 0x1, instead of the SCSI defined check condition value + * of 0x2. Host drivers are supposed to return the status + * byte as it is defined by SCSI. */ scp->result = DRIVER_BYTE(DRIVER_SENSE) | STATUS_BYTE(qdonep->d3.scsi_stat); @@ -3906,7 +4199,7 @@ break; default: - ASC_DBG1(0, "asc_isr_callback: done_stat %x\n", qdonep->d3.done_stat ); + ASC_PRINT1("asc_isr_callback: done_stat %x\n", qdonep->d3.done_stat ); scp->result = HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.scsi_msg) | STATUS_BYTE(qdonep->d3.scsi_stat); break; @@ -3917,18 +4210,15 @@ * triggering more commands to be issued, try to start any pending * commands. */ - if (ASC_BOARD(shp)->pending_tidmask != 0) { + if (boardp->pending.tidmask != 0) { /* * If there are any pending commands for this board before trying * to execute them, disable interrupts to preserve request ordering. */ - ASC_STATS(intr_disable); - save_flags(flags); - cli(); - ASC_DBG1(1, "asc_isr_callback: asc_execute_pending() %x\n", - ASC_BOARD(shp)->pending_tidmask); - asc_execute_pending(shp); - restore_flags(flags); + ASC_ASSERT(interrupts_enabled() == ASC_FALSE); + ASC_DBG1(1, "asc_isr_callback: asc_execute_queue() %x\n", + boardp->pending.tidmask); + asc_execute_queue(&boardp->pending); } /* @@ -3946,46 +4236,14 @@ } /* - * Execute as many pending requests as possible for the - * board specified by 'Scsi_Host'. - */ -STATIC void -asc_execute_pending(struct Scsi_Host *shp) -{ - ASC_SCSI_BIT_ID_TYPE scan_tidmask; - Scsi_Cmnd *scp; - int i; - - ASC_ASSERT(interrupts_enabled() == ASC_FALSE); - /* - * Execute pending commands for devices attached to - * the current board in round-robin fashion. - */ - scan_tidmask = ASC_BOARD(shp)->pending_tidmask; - do { - for (i = 0; i < ASC_MAX_TID; i++) { - if (scan_tidmask & ASC_TIX_TO_TARGET_ID(i)) { - if ((scp = asc_dequeue(shp, i)) == NULL) { - scan_tidmask &= ~ASC_TIX_TO_TARGET_ID(i); - } else if (asc_execute_scsi_cmnd(scp) == ASC_BUSY) { - scan_tidmask &= ~ASC_TIX_TO_TARGET_ID(i); - /* Put the request back at front of the list. */ - asc_enqueue(shp, scp, i, ASC_FRONT); - } - } - } - } while (scan_tidmask); - return; -} - -/* * asc_init_dev() * * Perform one-time initialization of a device. */ STATIC int -asc_init_dev(ASC_DVC_VAR *boardp, Scsi_Cmnd *scp) +asc_init_dev(ASC_DVC_VAR *asc_dvc_varp, Scsi_Cmnd *scp) { + struct asc_board *boardp; ASC_SCSI_REQ_Q *scsireqq; ASC_CAP_INFO *cap_info; ASC_SCSI_INQUIRY *inquiry; @@ -3999,10 +4257,10 @@ ASC_DBG1(1, "asc_init_dev: target %d\n", (unsigned) scp->target); - /* Return true for the board's target id. */ - if (boardp->cfg->chip_scsi_id == scp->target) { - return ASC_TRUE; - } + /* The hosts's target id is set in init_tidmask during initialization. */ + ASC_ASSERT(asc_dvc_varp->cfg->chip_scsi_id != scp->target); + + boardp = ASC_BOARDP(scp->host); /* * XXX - Host drivers should not modify the timeout field. @@ -4013,11 +4271,11 @@ scp->timeout += 2000; /* Add 5 seconds to the request timeout. */ /* Set-up AscInitPollTarget() arguments. */ - scsireqq = &ASC_BOARD(scp->host)->scsireqq; + scsireqq = &boardp->scsireqq; memset(scsireqq, 0, sizeof(ASC_SCSI_REQ_Q)); - cap_info = &ASC_BOARD(scp->host)->cap_info; + cap_info = &boardp->cap_info; memset(cap_info, 0, sizeof(ASC_CAP_INFO)); - inquiry = &ASC_BOARD(scp->host)->inquiry; + inquiry = &boardp->inquiry; memset(inquiry, 0, sizeof(ASC_SCSI_INQUIRY)); /* @@ -4026,12 +4284,13 @@ * AscInitPollEnd(). Normally all targets are initialized within * a call to AscInitPollBegin() and AscInitPollEnd(). */ - save_use_tagged_qng = boardp->use_tagged_qng; - save_can_tagged_qng = boardp->cfg->can_tagged_qng; + save_use_tagged_qng = asc_dvc_varp->use_tagged_qng; + save_can_tagged_qng = asc_dvc_varp->cfg->can_tagged_qng; ASC_DBG(2, "asc_init_dev: AscInitPollBegin()\n"); - if (AscInitPollBegin(boardp)) { - ASC_DBG(0, "asc_init_dev: AscInitPollBegin() failed\n"); + if (AscInitPollBegin(asc_dvc_varp)) { + ASC_PRINT1("asc_init_dev: Board %d: AscInitPollBegin() failed\n", + boardp->id); return ASC_FALSE; } @@ -4043,7 +4302,7 @@ found = ASC_FALSE; ASC_DBG(2, "asc_init_dev: AscInitPollTarget()\n"); - switch (ret = AscInitPollTarget(boardp, scsireqq, inquiry, cap_info)) { + switch (ret = AscInitPollTarget(asc_dvc_varp, scsireqq, inquiry, cap_info)) { case ASC_TRUE: found = ASC_TRUE; #ifdef ADVANSYS_DEBUG @@ -4052,19 +4311,19 @@ cap_info->lba, cap_info->blk_size); ASC_DBG1(1, "asc_init_dev: peri_dvc_type %x\n", inquiry->byte0.peri_dvc_type); - if (boardp->use_tagged_qng & tidmask) { + if (asc_dvc_varp->use_tagged_qng & tidmask) { ASC_DBG1(1, "asc_init_dev: command queuing enabled: %d\n", - boardp->max_dvc_qng[scp->target]); + asc_dvc_varp->max_dvc_qng[scp->target]); } else { ASC_DBG(1, "asc_init_dev: command queuing disabled\n"); } - if (boardp->init_sdtr & tidmask) { + if (asc_dvc_varp->init_sdtr & tidmask) { ASC_DBG(1, "asc_init_dev: synchronous transfers enabled\n"); } else { ASC_DBG(1, "asc_init_dev: synchronous transfers disabled\n"); } /* Set bit means fix disabled. */ - if (boardp->pci_fix_asyn_xfer & tidmask) { + if (asc_dvc_varp->pci_fix_asyn_xfer & tidmask) { ASC_DBG(1, "asc_init_dev: synchronous transfer fix disabled\n"); } else { ASC_DBG(1, "asc_init_dev: synchronous transfer fix enabled\n"); @@ -4075,31 +4334,22 @@ ASC_DBG(1, "asc_init_dev: no device found\n"); break; case ASC_ERROR: - ASC_DBG(0, "asc_init_dev: AscInitPollTarget() ASC_ERROR\n"); + ASC_PRINT1("asc_init_dev: Board %d: AscInitPollTarget() ASC_ERROR\n", + boardp->id); break; default: - ASC_DBG1(0, "asc_init_dev: AscInitPollTarget() unknown ret %d\n", ret); + ASC_PRINT2( +"asc_init_dev: Board %d: AscInitPollTarget() unknown ret %d\n", + boardp->id, ret); break; } /* XXX - 'Or' in original tag bits. */ - boardp->use_tagged_qng |= save_use_tagged_qng; - boardp->cfg->can_tagged_qng |= save_can_tagged_qng; + asc_dvc_varp->use_tagged_qng |= save_use_tagged_qng; + asc_dvc_varp->cfg->can_tagged_qng |= save_can_tagged_qng; ASC_DBG(2, "asc_init_dev: AscInitPollEnd()\n"); - AscInitPollEnd(boardp); - -#ifdef ASC_SET_CMD_PER_LUN - /* - * XXX - Refer to the comment in advansys_detect() - * regarding cmd_per_lun. - */ - for (i = 0; i <= ASC_MAX_TID; i++) { - if (boardp->max_dvc_qng[i] < scp->host->cmd_per_lun) { - scp->host->cmd_per_lun = boardp->max_dvc_qng[i]; - } - } -#endif /* ASC_SET_CMD_PER_LUN */ + AscInitPollEnd(asc_dvc_varp); return found; } @@ -4111,15 +4361,15 @@ asc_srch_pci_dev(PCI_DEVICE *pciDevice) { int ret; - static int scan = 1; ASC_DBG(2, "asc_srch_pci_dev: begin\n"); - if (scan) { - pciDevice->type = asc_scan_method(pciDevice); - scan = 0; - ASC_DBG1(2, "asc_srch_pci_dev: type %d\n", pciDevice->type); + if (pci_scan_method == -1) { + pci_scan_method = asc_scan_method(); } + pciDevice->type = pci_scan_method; + ASC_DBG1(2, "asc_srch_pci_dev: type %d\n", pciDevice->type); + ret = asc_pci_find_dev(pciDevice); ASC_DBG1(2, "asc_srch_pci_dev: asc_pci_find_dev() return %d\n", ret); if (ret == PCI_DEVICE_FOUND) { @@ -4134,7 +4384,7 @@ pciDevice->startSlot = 0; pciDevice->endSlot = 0x0f; ret = asc_srch_pci_dev(pciDevice); - ASC_DBG1(2, "asc_srch_pci_dev recursive call return %d\n", ret); + ASC_DBG1(2, "asc_srch_pci_dev: recursive call return %d\n", ret); } } ASC_DBG1(2, "asc_srch_pci_dev: return %d\n", ret); @@ -4145,7 +4395,7 @@ * Determine the access method to be used for 'pciDevice'. */ STATIC uchar -asc_scan_method(PCI_DEVICE *pciDevice) +asc_scan_method(void) { ushort data; PCI_DATA pciData; @@ -4197,8 +4447,9 @@ deviceid = asc_get_cfg_word(&pciData); ASC_DBG1(3, "asc_pci_find_dev: deviceid %x\n", deviceid); if ((vendorid == ASC_PCI_VENDORID) && - ((deviceid == ASC_PCI_DEVICE_ID_REV_A) || - (deviceid == ASC_PCI_DEVICE_ID_REV_B))) { + ((deviceid == ASC_PCI_DEVICE_ID_1100) || + (deviceid == ASC_PCI_DEVICE_ID_1200) || + (deviceid == ASC_PCI_DEVICE_ID_1300))) { pciDevice->slotFound = lslot; ASC_DBG(3, "asc_pci_find_dev: PCI_DEVICE_FOUND\n"); return PCI_DEVICE_FOUND; @@ -4255,29 +4506,29 @@ STATIC ushort asc_get_cfg_word(PCI_DATA *pciData) { - ushort tmp; - ulong address; - ulong lbus = pciData->bus; - ulong lslot = pciData->slot; - ulong lfunc = pciData->func; - uchar t2CFA, t2CF8; - ushort t1CF8, t1CFA, t1CFC, t1CFE; + ushort tmp; + ulong address; + ulong lbus = pciData->bus; + ulong lslot = pciData->slot; + ulong lfunc = pciData->func; + uchar t2CFA, t2CF8; + ulong t1CF8, t1CFC; ASC_DBG4(4, "asc_get_cfg_word: type %d, bus %lu, slot %lu, func %lu\n", pciData->type, lbus, lslot, lfunc); /* - * check type of configuration mechanism + * Check type of configuration mechanism. */ if (pciData->type == 2) { /* - * save these registers so we can restore them after we are done + * Save registers to be restored later. */ t2CFA = inp(0xCFA); /* save PCI bus register */ t2CF8 = inp(0xCF8); /* save config space enable register */ /* - * go out and write the bus and enable registers + * Write the bus and enable registers. */ /* set for type 1 cycle, if needed */ outp(0xCFA, pciData->bus); @@ -4285,19 +4536,20 @@ outp(0xCF8, 0x10 | (pciData->func << 1)) ; /* - * read the configuration space type 2 locations + * Read the configuration space type 2 locations. */ tmp = (ushort) inpw(0xC000 | ((pciData->slot << 8) + pciData->offset)); + + outp(0xCFA, t2CFA); /* save PCI bus register */ + outp(0xCF8, t2CF8); /* save config space enable register */ } else { /* - * type 1 configuration mechanism + * Type 1 or 3 configuration mechanism. * - * save the CONFIG_ADDRESS and CONFIG_DATA register values + * Save the CONFIG_ADDRESS and CONFIG_DATA register values. */ - t1CFC = inpw(0xCFC); - t1CFE = inpw(0xCFE); - t1CF8 = inpw(0xCF8); - t1CFA = inpw(0xCFA); + t1CF8 = inpl(0xCF8); + t1CFC = inpl(0xCFC); /* * enable <31>, bus = <23:16>, slot = <15:11>, @@ -4307,15 +4559,21 @@ (lfunc << 8) | (pciData->offset & 0xFC) | 0x80000000L); /* - * write out the address to CONFIG_ADDRESS + * Write out the address to CONFIG_ADDRESS. */ - outl(address, 0xCF8); + outpl(0xCF8, address); /* - * read in the word from CONFIG_DATA + * Read in word from CONFIG_DATA. */ - tmp = (ushort) ((inl(0xCFC) >> + tmp = (ushort) ((inpl(0xCFC) >> ((pciData->offset & 2) * 8)) & 0xFFFF); + + /* + * Restore registers. + */ + outpl(0xCF8, t1CF8); + outpl(0xCFC, t1CFC); } ASC_DBG1(4, "asc_get_cfg_word: config data: %x\n", tmp); return tmp; @@ -4333,22 +4591,22 @@ ulong address; ulong lbus = pciData->bus, lslot = pciData->slot, lfunc = pciData->func; uchar t2CFA, t2CF8; - ushort t1CF8, t1CFA, t1CFC, t1CFE; + ulong t1CF8, t1CFC; ASC_DBG1(4, "asc_get_cfg_byte: type: %d\n", pciData->type); /* - * check type of configuration mechanism + * Check type of configuration mechanism. */ if (pciData->type == 2) { /* - * save these registers so we can restore them after we are done + * Save registers to be restored later. */ t2CFA = inp(0xCFA); /* save PCI bus register */ t2CF8 = inp(0xCF8); /* save config space enable register */ /* - * go out and write the bus and enable registers + * Write the bus and enable registers. */ /* set for type 1 cycle, if needed */ outp(0xCFA, pciData->bus); @@ -4356,25 +4614,23 @@ outp(0xCF8, 0x10 | (pciData->func << 1)); /* - * read the configuration space type 2 locations + * Read configuration space type 2 locations. */ tmp = inp(0xC000 | ((pciData->slot << 8) + pciData->offset)); /* - * restore the registers used for our transaction + * Restore registers. */ outp(0xCF8, t2CF8); /* restore the enable register */ outp(0xCFA, t2CFA); /* restore PCI bus register */ } else { /* - * type 1 configuration mechanism + * Type 1 or 3 configuration mechanism. * - * save the CONFIG_ADDRESS and CONFIG_DATA register values + * Save CONFIG_ADDRESS and CONFIG_DATA register values. */ - t1CFC = inpw(0xCFC); - t1CFE = inpw(0xCFE); - t1CF8 = inpw(0xCF8); - t1CFA = inpw(0xCFA); + t1CF8 = inpl(0xCF8); + t1CFC = inpl(0xCFC); /* * enable <31>, bus = <23:16>, slot = <15:11>, func = <10:8>, @@ -4384,104 +4640,636 @@ (lfunc << 8) | (pciData->offset & 0xFC) | 0x80000000L); /* - * write out the address to CONFIG_ADDRESS + * Write out address to CONFIG_ADDRESS. + */ + outpl(0xCF8, address); + + /* + * Read in word from CONFIG_DATA. */ - outl(address, 0xCF8); + tmp = (uchar) ((inpl(0xCFC) >> ((pciData->offset & 3) * 8)) & 0xFF); /* - * read in the word from CONFIG_DATA + * Restore registers. */ - tmp = (uchar) ((inl(0xCFC) >> ((pciData->offset & 3) * 8)) & 0xFF); + outpl(0xCF8, t1CF8); + outpl(0xCFC, t1CFC); } ASC_DBG1(4, "asc_get_cfg_byte: config data: %x\n", tmp); return tmp; } /* - * Add a 'Scsi_Cmnd' to the end of specified 'Scsi_Host' - * target device pending command list. Set 'pending_tidmask' + * Write a byte to the PCI configuration space. + */ +void +asc_put_cfg_byte(PCI_DATA *pciData, uchar byte_data) +{ + ulong tmpl; + ulong address; + ulong lbus = pciData->bus, lslot = pciData->slot, lfunc = pciData->func; + uchar t2CFA, t2CF8; + ulong t1CF8, t1CFC; + + ASC_DBG2(4, "asc_put_cfg_byte: type: %d, byte_data %x\n", + pciData->type, byte_data); + + /* + * Check type of configuration mechanism. + */ + if (pciData->type == 2) { + + /* + * Save registers to be restored later. + */ + t2CFA = inp(0xCFA); /* save PCI bus register */ + t2CF8 = inp(0xCF8); /* save config space enable register */ + + /* + * Write bus and enable registers. + */ + outp(0xCFA, pciData->bus); + + /* + * Set the function number. + */ + outp(0xCF8, 0x10 | (pciData->func << 1)); + + /* + * Write the configuration space type 2 locations. + */ + outp(0xC000 | ((pciData->slot << 8) + pciData->offset), byte_data); + + /* + * Restore registers. + */ + outp(0xCF8, t2CF8); /* restore the enable register */ + outp(0xCFA, t2CFA); /* restore PCI bus register */ + } else { + + /* + * Type 1 or 3 configuration mechanism. + * + * Save the CONFIG_ADDRESS and CONFIG_DATA register values. + */ + t1CF8 = inpl(0xCF8); + t1CFC = inpl(0xCFC); + + /* + * enable <31>, bus = <23:16>, slot = <15:11>, func = <10:8>, + * reg = <7:2> + */ + address = (ulong) ((lbus << 16) | (lslot << 11) | (lfunc << 8) | + (pciData->offset & 0xFC) | 0x80000000L); + /* + * Write out address to CONFIG_ADDRESS. + */ + outpl(0xCF8, address); + + /* + * Write double word to CONFIG_DATA preserving the bytes + * in the double not written. + */ + tmpl = inpl(0xCFC) & ~(0xFF << ((pciData->offset & 3) * 8)); + outpl(0xCFC, tmpl | (byte_data << ((pciData->offset & 3) * 8))); + + /* + * Restore registers. + */ + outpl(0xCF8, t1CF8); + outpl(0xCFC, t1CFC); + } + ASC_DBG(4, "asc_put_cfg_byte: end\n"); +} + +/* + * Add a 'REQP' to the end of specified queue. Set 'tidmask' * to indicate a command is queued for the device. * * 'flag' may be either ASC_FRONT or ASC_BACK. * - * The 'Scsi_Cmnd' host_scribble field is used as a next pointer. + * 'REQPNEXT(reqp)' returns reqp's next pointer. */ -STATIC void -asc_enqueue(struct Scsi_Host *shp, Scsi_Cmnd *scp, int tid, int flag) +void +asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag) { - Scsi_Cmnd **scpp; + REQP *reqpp; + int tid; ASC_ASSERT(interrupts_enabled() == ASC_FALSE); + ASC_DBG3(2, "asc_enqueue: ascq %x, reqp %x, flag %d\n", + (unsigned) ascq, (unsigned) reqp, flag); + tid = REQPTID(reqp); ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK); - ASC_STATS(enqueue); if (flag == ASC_FRONT) { - scp->host_scribble = (unsigned char *) ASC_BOARD(shp)->pending[tid]; - ASC_BOARD(shp)->pending[tid] = (Scsi_Cmnd *) scp; + REQPNEXT(reqp) = ascq->queue[tid]; + ascq->queue[tid] = reqp; } else { /* ASC_BACK */ - for (scpp = &ASC_BOARD(shp)->pending[tid]; *scpp; - scpp = (Scsi_Cmnd **) &(*scpp)->host_scribble) { + for (reqpp = &ascq->queue[tid]; *reqpp; reqpp = REQPNEXTP(*reqpp)) { + ASC_ASSERT(ascq->tidmask & ASC_TIX_TO_TARGET_ID(tid)); ; } - *scpp = scp; - scp->host_scribble = NULL; + *reqpp = reqp; + REQPNEXT(reqp) = NULL; } - ASC_BOARD(shp)->pending_tidmask |= ASC_TIX_TO_TARGET_ID(tid); + /* The queue has at least one entry, set its bit. */ + ascq->tidmask |= ASC_TIX_TO_TARGET_ID(tid); +#ifdef ADVANSYS_STATS + /* + * Maintain request queue statistics. + */ + ascq->cur_count[tid]++; + if (ascq->cur_count[tid] > ascq->max_count[tid]) { + ascq->max_count[tid] = ascq->cur_count[tid]; + ASC_DBG2(1, "asc_enqueue: new max_count[%d] %d\n", + tid, ascq->max_count[tid]); + } +#endif /* ADVANSYS_STATS */ + ASC_DBG1(1, "asc_enqueue: reqp %x\n", (unsigned) reqp); + return; } /* - * Return first pending 'Scsi_Cmnd' on the specified 'Scsi_Host' - * for the specified target device. Clear the 'pending_tidmask' - * bit for the device if no more commands are left queued for it. + * Return first queued 'REQP' on the specified queue for + * the specified target device. Clear the 'tidmask' bit for + * the device if no more commands are left queued for it. * - * The 'Scsi_Cmnd' host_scribble field is used as a next pointer. + * 'REQPNEXT(reqp)' returns reqp's next pointer. */ -STATIC Scsi_Cmnd * -asc_dequeue(struct Scsi_Host *shp, int tid) +REQP +asc_dequeue(asc_queue_t *ascq, int tid) { - Scsi_Cmnd *scp; + REQP reqp; - ASC_STATS(dequeue); ASC_ASSERT(interrupts_enabled() == ASC_FALSE); - if ((scp = ASC_BOARD(shp)->pending[tid]) != NULL) { - ASC_BOARD(shp)->pending[tid] = (Scsi_Cmnd *) scp->host_scribble; + ASC_DBG2(1, "asc_dequeue: ascq %x, tid %d\n", (unsigned) ascq, tid); + if ((reqp = ascq->queue[tid]) != NULL) { + ASC_ASSERT(ascq->tidmask & ASC_TIX_TO_TARGET_ID(tid)); + ascq->queue[tid] = REQPNEXT(reqp); + /* If the queue is empty, clear its bit. */ + if (ascq->queue[tid] == NULL) { + ascq->tidmask &= ~ASC_TIX_TO_TARGET_ID(tid); + } } - if (ASC_BOARD(shp)->pending[tid] == NULL) { - ASC_BOARD(shp)->pending_tidmask &= ~ASC_TIX_TO_TARGET_ID(tid); +#ifdef ADVANSYS_STATS + /* + * Maintain request queue statistics. + */ + if (reqp != NULL) { + ascq->cur_count[tid]--; } - return scp; + ASC_ASSERT(ascq->cur_count[tid] >= 0); +#endif /* ADVANSYS_STATS */ + ASC_DBG1(1, "asc_dequeue: reqp %x\n", (unsigned) reqp); + return reqp; } /* - * Remove the specified 'Scsi_Cmnd' from the specified 'Scsi_Host' - * for the specified target device. Clear the 'pending_tidmask' - * bit for the device if no more commands are left queued for it. + * Remove the specified 'REQP' from the specified queue for + * the specified target device. Clear the 'tidmask' bit for the + * device if no more commands are left queued for it. * - * The 'Scsi_Cmnd' host_scribble field is used as a next pointer. + * 'REQPNEXT(reqp)' returns reqp's the next pointer. * - * Return ASC_TRUE if the command was found and removed, otherwise - * return ASC_FALSE if the command was not found. + * Return ASC_TRUE if the command was found and removed, + * otherwise return ASC_FALSE. */ -STATIC int -asc_rmqueue(struct Scsi_Host *shp, Scsi_Cmnd *scp, int tid) +int +asc_rmqueue(asc_queue_t *ascq, REQP reqp) { - Scsi_Cmnd **scpp; + REQP *reqpp; + int tid; int ret; ASC_ASSERT(interrupts_enabled() == ASC_FALSE); ret = ASC_FALSE; - for (scpp = &ASC_BOARD(shp)->pending[tid]; - *scpp; scpp = (Scsi_Cmnd **) &(*scpp)->host_scribble) { - if (*scpp == scp) { - *scpp = (Scsi_Cmnd *) scp->host_scribble; - scp->host_scribble = NULL; - ASC_STATS(rmqueue); + tid = REQPTID(reqp); + for (reqpp = &ascq->queue[tid]; *reqpp; reqpp = REQPNEXTP(*reqpp)) { + ASC_ASSERT(ascq->tidmask & ASC_TIX_TO_TARGET_ID(tid)); + if (*reqpp == reqp) { ret = ASC_TRUE; - break; /* Note: Don't iterate, *scpp may be NULL. */ + *reqpp = REQPNEXT(reqp); + REQPNEXT(reqp) = NULL; + /* If the queue is now empty, clear its bit. */ + if (ascq->queue[tid] == NULL) { + ascq->tidmask &= ~ASC_TIX_TO_TARGET_ID(tid); + } + break; /* Note: *reqpp may now be NULL, don't iterate. */ + } + } +#ifdef ADVANSYS_STATS + /* + * Maintain request queue statistics. + */ + if (ret == ASC_TRUE) { + ascq->cur_count[tid]--; + } + ASC_ASSERT(ascq->cur_count[tid] >= 0); +#endif /* ADVANSYS_STATS */ + ASC_DBG2(1, "asc_rmqueue: reqp %x, ret %d\n", (unsigned) reqp, ret); + return ret; +} + +/* + * If the specified 'REQP' is queued on the specified queue for + * the specified target device, return ASC_TRUE. + */ +int +asc_isqueued(asc_queue_t *ascq, REQP reqp) +{ + REQP *reqpp; + int tid; + int ret; + + ASC_ASSERT(interrupts_enabled() == ASC_FALSE); + ret = ASC_FALSE; + tid = REQPTID(reqp); + for (reqpp = &ascq->queue[tid]; *reqpp; reqpp = REQPNEXTP(*reqpp)) { + ASC_ASSERT(ascq->tidmask & ASC_TIX_TO_TARGET_ID(tid)); + if (*reqpp == reqp) { + ret = ASC_TRUE; + break; + } + } + return ret; +} + +/* + * Execute as many queued requests as possible for the specified queue. + * + * Calls asc_execute_scsi_cmnd() to execute a REQP/Scsi_Cmnd. + */ +void +asc_execute_queue(asc_queue_t *ascq) +{ + ASC_SCSI_BIT_ID_TYPE scan_tidmask; + REQP reqp; + int i; + + ASC_ASSERT(interrupts_enabled() == ASC_FALSE); + ASC_DBG1(1, "asc_execute_queue: ascq %x\n", (unsigned) ascq); + /* + * Execute queued commands for devices attached to + * the current board in round-robin fashion. + */ + scan_tidmask = ascq->tidmask; + do { + for (i = 0; i <= ASC_MAX_TID; i++) { + if (scan_tidmask & ASC_TIX_TO_TARGET_ID(i)) { + if ((reqp = asc_dequeue(ascq, i)) == NULL) { + scan_tidmask &= ~ASC_TIX_TO_TARGET_ID(i); + } else if (asc_execute_scsi_cmnd((Scsi_Cmnd *) reqp) + == ASC_BUSY) { + scan_tidmask &= ~ASC_TIX_TO_TARGET_ID(i); + /* Put the request back at front of the list. */ + asc_enqueue(ascq, reqp, ASC_FRONT); + } + } + } + } while (scan_tidmask); + return; +} + +/* + * asc_prt_board_devices() + * + * Print driver information for devices attached to the board. + * + * Note: no single line should be greater than ASC_PRTLINE_SIZE, + * cf. asc_prt_line(). + * + * Return the number of characters copied into 'cp'. No more than + * 'cplen' characters will be copied to 'cp'. + */ +STATIC int +asc_prt_board_devices(struct Scsi_Host *shp, char *cp, int cplen) +{ + struct asc_board *boardp; + int leftlen; + int totlen; + int len; + int i; + + boardp = ASC_BOARDP(shp); + leftlen = cplen; + totlen = len = 0; + + len = asc_prt_line(cp, leftlen, +"\nDevice Information for AdvanSys SCSI Host %d:\n", shp->host_no); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, "Target Ids Detected:"); + ASC_PRT_NEXT(); + for (i = 0; i <= ASC_MAX_TID; i++) { + if (boardp->asc_dvc_cfg.chip_scsi_id == i) { + continue; + } else if (boardp->init_tidmask & (1 << i)) { + len = asc_prt_line(cp, leftlen, " %d,", i); + ASC_PRT_NEXT(); } } - if (ASC_BOARD(shp)->pending[tid] == NULL) { - ASC_BOARD(shp)->pending_tidmask &= ~ASC_TIX_TO_TARGET_ID(tid); + len = asc_prt_line(cp, leftlen, " (%d=Host Adapter)\n", + boardp->asc_dvc_cfg.chip_scsi_id); + ASC_PRT_NEXT(); + + return totlen; +} + +/* + * asc_prt_board_eeprom() + * + * Print board EEPROM configuration. + * + * Note: no single line should be greater than ASC_PRTLINE_SIZE, + * cf. asc_prt_line(). + * + * Return the number of characters copied into 'cp'. No more than + * 'cplen' characters will be copied to 'cp'. + */ +STATIC int +asc_prt_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen) +{ + struct asc_board *boardp; + ASC_DVC_VAR *asc_dvc_varp; + int leftlen; + int totlen; + int len; + ASCEEP_CONFIG *ep; + int i; + int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 }; + + boardp = ASC_BOARDP(shp); + asc_dvc_varp = &boardp->asc_dvc_var; + ep = &boardp->eep_config; + + leftlen = cplen; + totlen = len = 0; + + len = asc_prt_line(cp, leftlen, +"\nEEPROM Settings for AdvanSys SCSI Host %d:\n", shp->host_no); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n", + ep->chip_scsi_id, ep->max_total_qng, ep->max_tag_qng); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Disconnects: "); + ASC_PRT_NEXT(); + for (i = 0; i <= ASC_MAX_TID; i++) { + len = asc_prt_line(cp, leftlen, " %d:%c", + i, (ep->disc_enable & (1 << i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Command Queuing: "); + ASC_PRT_NEXT(); + for (i = 0; i <= ASC_MAX_TID; i++) { + len = asc_prt_line(cp, leftlen, " %d:%c", + i, (ep->use_cmd_qng & (1 << i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Start Motor: "); + ASC_PRT_NEXT(); + for (i = 0; i <= ASC_MAX_TID; i++) { + len = asc_prt_line(cp, leftlen, " %d:%c", + i, (ep->start_motor & (1 << i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Synchronous Transfer:"); + ASC_PRT_NEXT(); + for (i = 0; i <= ASC_MAX_TID; i++) { + len = asc_prt_line(cp, leftlen, " %d:%c", + i, (ep->init_sdtr & (1 << i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + if (asc_dvc_varp->bus_type & ASC_IS_ISA) { + len = asc_prt_line(cp, leftlen, +" Host ISA DMA speed: %d MB/S\n", + isa_dma_speed[ep->isa_dma_speed]); + ASC_PRT_NEXT(); + } + + return totlen; +} + +/* + * asc_prt_board_info() + * + * Print dynamic board configuration information. + * + * Note: no single line should be greater than ASC_PRTLINE_SIZE, + * cf. asc_prt_line(). + * + * Return the number of characters copied into 'cp'. No more than + * 'cplen' characters will be copied to 'cp'. + */ +STATIC int +asc_prt_board_info(struct Scsi_Host *shp, char *cp, int cplen) +{ + struct asc_board *boardp; + int leftlen; + int totlen; + int len; + ASC_DVC_VAR *v; + ASC_DVC_CFG *c; + int i; +#ifdef ADVANSYS_STATS + struct asc_stats *s; +#endif /* ADVANSYS_STATS */ + + boardp = ASC_BOARDP(shp); + v = &boardp->asc_dvc_var; + c = &boardp->asc_dvc_cfg; + + leftlen = cplen; + totlen = len = 0; + + len = asc_prt_line(cp, leftlen, +"\nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:\n", + shp->host_no); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" chip_version %u, lib_version %u, lib_serial_no %u mcode_date %u\n", + c->chip_version, c->lib_version, c->lib_serial_no, c->mcode_date); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" mcode_version %u, err_code %u\n", + c->mcode_version, v->err_code); + ASC_PRT_NEXT(); + + /* Current number of commands pending for the host. */ + len = asc_prt_line(cp, leftlen, +" Total Command Pending: %d\n", v->cur_total_qng); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Synchronous Transfer: "); + ASC_PRT_NEXT(); + for (i = 0; i <= ASC_MAX_TID; i++) { + if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || + ((boardp->init_tidmask & (1 << i)) == 0)) { + continue; + } + len = asc_prt_line(cp, leftlen, " %d:%c", + i, (v->sdtr_done & (1 << i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" Command Queuing: "); + ASC_PRT_NEXT(); + for (i = 0; i <= ASC_MAX_TID; i++) { + if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || + ((boardp->init_tidmask & (1 << i)) == 0)) { + continue; + } + len = asc_prt_line(cp, leftlen, " %d:%c", + i, (v->use_tagged_qng & (1 << i)) ? 'Y' : 'N'); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + /* Current number of commands pending for a device. */ + len = asc_prt_line(cp, leftlen, +" Command Queue Pending: "); + ASC_PRT_NEXT(); + for (i = 0; i <= ASC_MAX_TID; i++) { + if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || + ((boardp->init_tidmask & (1 << i)) == 0)) { + continue; + } + len = asc_prt_line(cp, leftlen, " %d:%u", i, v->cur_dvc_qng[i]); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + + /* Current limit on number of commands that can be sent to a device. */ + len = asc_prt_line(cp, leftlen, +" Command Queue Limit: "); + ASC_PRT_NEXT(); + for (i = 0; i <= ASC_MAX_TID; i++) { + if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || + ((boardp->init_tidmask & (1 << i)) == 0)) { + continue; + } + len = asc_prt_line(cp, leftlen, " %d:%u", i, v->max_dvc_qng[i]); + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); + +#ifdef ADVANSYS_STATS + s = &boardp->asc_stats; + + /* Indicate whether the device has returned queue full status. */ + len = asc_prt_line(cp, leftlen, +" Command Queue Full: "); + ASC_PRT_NEXT(); + for (i = 0; i <= ASC_MAX_TID; i++) { + if ((boardp->asc_dvc_cfg.chip_scsi_id == i) || + ((boardp->init_tidmask & (1 << i)) == 0)) { + continue; + } + if (s->queue_full & (1 << i)) { + len = asc_prt_line(cp, leftlen, " %d:Y-%d", + i, s->queue_full_cnt[i]); + } else { + len = asc_prt_line(cp, leftlen, " %d:N", i); + } + ASC_PRT_NEXT(); + } + len = asc_prt_line(cp, leftlen, "\n"); + ASC_PRT_NEXT(); +#endif /* ADVANSYS_STATS */ + + return totlen; +} + +#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0) +/* + * asc_proc_copy() + * + * Copy proc information to a read buffer taking into account the current + * read offset in the file and the remaining space in the read buffer. + */ +STATIC int +asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen, + char *cp, int cplen) +{ + int cnt = 0; + + ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n", + (unsigned) offset, (unsigned) advoffset, cplen); + if (offset <= advoffset) { + /* Read offset below current offset, copy everything. */ + cnt = ASC_MIN(cplen, leftlen); + ASC_DBG3(2, "asc_proc_copy: curbuf %x, cp %x, cnt %d\n", + (unsigned) curbuf, (unsigned) cp, cnt); + memcpy(curbuf, cp, cnt); + } else if (offset < advoffset + cplen) { + /* Read offset within current range, partial copy. */ + cnt = (advoffset + cplen) - offset; + cp = (cp + cplen) - cnt; + cnt = ASC_MIN(cnt, leftlen); + ASC_DBG3(2, "asc_proc_copy: curbuf %x, cp %x, cnt %d\n", + (unsigned) curbuf, (unsigned) cp, cnt); + memcpy(curbuf, cp, cnt); + } + return cnt; +} +#endif /* version >= v1.3.0 */ + +/* + * asc_prt_line() + * + * If 'cp' is NULL print to the console, otherwise print to a buffer. + * + * Return 0 if printing to the console, otherwise return the number of + * bytes written to the buffer. + * + * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack + * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes. + */ +int +asc_prt_line(char *buf, int buflen, char *fmt, ...) +{ + va_list args; + int ret; + char s[ASC_PRTLINE_SIZE]; + + va_start(args, fmt); + ret = vsprintf(s, fmt, args); + ASC_ASSERT(ret < ASC_PRTLINE_SIZE); + if (buf == NULL) { + (void) printk(s); + ret = 0; + } else { + ret = ASC_MIN(buflen, ret); + memcpy(buf, s, ret); } + va_end(args); return ret; } @@ -4578,7 +5366,7 @@ if (i == 2 || i == 10) { continue; } - AscPutChipLramData(iop_base, *outbuf); + AscSetChipLramDataNoSwap(iop_base, *outbuf); } } @@ -4602,7 +5390,7 @@ if (i == 5) { continue; } - *inbuf = AscGetChipLramData(iop_base); + *inbuf = AscGetChipLramDataNoSwap(iop_base); } ASC_DBG_PRT_HEX(2, "DvcGetQinfo", (uchar *) inbuf, 2 * words); } @@ -4669,111 +5457,207 @@ return; } +/* + * Read a PCI configuration byte. + */ +uchar +DvcReadPCIConfigByte( + ASC_DVC_VAR asc_ptr_type *asc_dvc, + ushort offset ) +{ + PCI_DATA pciData; + + pciData.bus = ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info); + pciData.slot = ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info); + pciData.func = ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info); + pciData.offset = offset; + pciData.type = pci_scan_method; + return asc_get_cfg_byte(&pciData); +} /* - * --- Tracing and Debugging Functions + * Write a PCI configuration byte. */ +void +DvcWritePCIConfigByte( + ASC_DVC_VAR asc_ptr_type *asc_dvc, + ushort offset, + uchar byte_data ) +{ + PCI_DATA pciData; -#ifdef ADVANSYS_STATS + pciData.bus = ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info); + pciData.slot = ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info); + pciData.func = ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info); + pciData.offset = offset; + pciData.type = pci_scan_method; + asc_put_cfg_byte(&pciData, byte_data); +} -#define ASC_PRT_STATS_NEXT() \ - if (cp) { \ - totlen += len; \ - leftlen -= len; \ - if (leftlen == 0) { \ - return totlen; \ - } \ - cp += len; \ - } +/* + * Return the BIOS address of the adatper at the specified + * I/O port and with the specified bus type. + * + * This function was formerly supplied by the library. + */ +ushort +AscGetChipBiosAddress( + PortAddr iop_base, + ushort bus_type + ) +{ + ushort cfg_lsw ; + ushort bios_addr ; + + /* + * We can't get the BIOS address for PCI + */ + if ( bus_type & ASC_IS_PCI ) + { + return( 0 ); + } + + if( ( bus_type & ASC_IS_EISA ) != 0 ) + { + cfg_lsw = AscGetEisaChipCfg( iop_base ) ; + cfg_lsw &= 0x000F ; + bios_addr = ( ushort )( ASC_BIOS_MIN_ADDR + + ( cfg_lsw * ASC_BIOS_BANK_SIZE ) ) ; + return( bios_addr ) ; + }/* if */ + + cfg_lsw = AscGetChipCfgLsw( iop_base ) ; + + /* + * ISA PnP uses the top bit as the 32K BIOS flag + */ + if ( bus_type == ASC_IS_ISAPNP ) + { + cfg_lsw &= 0x7FFF; + }/* if */ + + bios_addr = ( ushort )( ( ( cfg_lsw >> 12 ) * ASC_BIOS_BANK_SIZE ) + + ASC_BIOS_MIN_ADDR ) ; + return( bios_addr ) ; +} + + +/* + * --- Tracing and Debugging Functions + */ +#ifdef ADVANSYS_STATS /* - * asc_prt_stats() + * asc_prt_board_stats() * - * Note: no single line should be greater than 160 characters, cf. - * asc_prt_stats_line(). + * Note: no single line should be greater than ASC_PRTLINE_SIZE, + * cf. asc_prt_line(). * * Return the number of characters copied into 'cp'. No more than * 'cplen' characters will be copied to 'cp'. */ STATIC int -asc_prt_stats(char *cp, int cplen) +asc_prt_board_stats(struct Scsi_Host *shp, char *cp, int cplen) { - struct asc_stats *s; int leftlen; int totlen; int len; + struct asc_stats *s; + int i; + asc_queue_t *active; + asc_queue_t *pending; - s = &asc_stats; leftlen = cplen; totlen = len = 0; - len = asc_prt_stats_line(cp, leftlen, -"\nAdvanSys SCSI Host Driver Statistics:\n"); - ASC_PRT_STATS_NEXT(); + s = &ASC_BOARDP(shp)->asc_stats; + len = asc_prt_line(cp, leftlen, +"\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n", shp->host_no); + ASC_PRT_NEXT(); - len = asc_prt_stats_line(cp, leftlen, -" command %lu, queuecommand %lu, abort %lu, reset %lu, biosparam %lu,\n", + len = asc_prt_line(cp, leftlen, +" command %lu, queuecommand %lu, abort %lu, reset %lu, biosparam %lu\n", s->command, s->queuecommand, s->abort, s->reset, s->biosparam); - ASC_PRT_STATS_NEXT(); + ASC_PRT_NEXT(); - len = asc_prt_stats_line(cp, leftlen, -" interrupt %lu, callback %lu, cmd_disable %lu, intr_disable %lu,\n", - s->interrupt, s->callback, s->cmd_disable, s->intr_disable); - ASC_PRT_STATS_NEXT(); - - len = asc_prt_stats_line(cp, leftlen, -" error %lu, enqueue %lu, dequeue %lu, rmqueue %lu,\n", - s->error, s->enqueue, s->dequeue, s->rmqueue); - ASC_PRT_STATS_NEXT(); + len = asc_prt_line(cp, leftlen, +" check_interrupt %lu, interrupt %lu, callback %lu\n", + s->check_interrupt, s->interrupt, s->callback); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, +" asc_noerror %lu, asc_busy %lu, asc_error %lu, asc_unknown %lu\n", + s->asc_noerror, s->asc_busy, s->asc_error, s->asc_unknown); + ASC_PRT_NEXT(); + + /* + * Display request queuing statistics. + */ + len = asc_prt_line(cp, leftlen, +" Active and Pending Request Queues:\n"); + ASC_PRT_NEXT(); + + active = &ASC_BOARDP(shp)->active; + pending = &ASC_BOARDP(shp)->pending; + for (i = 0; i < ASC_MAX_TID + 1; i++) { + if (active->max_count[i] > 0 || pending->max_count[i] > 0) { + len = asc_prt_line(cp, leftlen, +" target %d: active [cur %d, max %d], pending [cur %d, max %d]\n", + i, active->cur_count[i], active->max_count[i], + pending->cur_count[i], pending->max_count[i]); + ASC_PRT_NEXT(); + } + } + /* + * Display data transfer statistics. + */ if (s->cont_cnt > 0) { - len = asc_prt_stats_line(cp, leftlen, -" cont_cnt %lu, cont_xfer %lu: avg_xfer=%lu kb\n", - s->cont_cnt, s->cont_xfer, (s->cont_xfer/2)/s->cont_cnt); - ASC_PRT_STATS_NEXT(); + len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ", + s->cont_xfer/2, + ASC_TENTHS(s->cont_xfer, 2)); + ASC_PRT_NEXT(); + + /* Contiguous transfer average size */ + len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n", + (s->cont_xfer/2)/s->cont_cnt, + ASC_TENTHS((s->cont_xfer/2), s->cont_cnt)); + ASC_PRT_NEXT(); } if (s->sg_cnt > 0) { - len = asc_prt_stats_line(cp, leftlen, -" sg_cnt %lu, sg_elem %lu, sg_xfer %lu: avg_elem=%lu, avg_size=%lu kb\n", - s->sg_cnt, s->sg_elem, s->sg_xfer, - s->sg_elem/s->sg_cnt, (s->sg_xfer/2)/s->sg_cnt); - ASC_PRT_STATS_NEXT(); + + len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ", + s->sg_cnt, s->sg_elem); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kb\n", + s->sg_xfer/2, + ASC_TENTHS(s->sg_xfer, 2)); + ASC_PRT_NEXT(); + + /* Scatter gather transfer statistics */ + len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ", + s->sg_elem/s->sg_cnt, + ASC_TENTHS(s->sg_elem, s->sg_cnt)); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ", + (s->sg_xfer/2)/s->sg_elem, + ASC_TENTHS((s->sg_xfer/2), s->sg_elem)); + ASC_PRT_NEXT(); + + len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n", + (s->sg_xfer/2)/s->sg_cnt, + ASC_TENTHS((s->sg_xfer/2), s->sg_cnt)); + ASC_PRT_NEXT(); } return totlen; } - -/* - * asc_prt_stats_line() - * - * If 'cp' is NULL print to the console, otherwise print to a buffer. - * - * Return 0 if printing to the console, otherwise return the number of - * bytes written to the buffer. - * - * Note: If any single line is greater than 160 bytes the stack - * will be corrupted. 's[]' is defined to be 160 bytes. - */ -int -asc_prt_stats_line(char *buf, int buflen, char *fmt, ...) -{ - va_list args; - int ret; - char s[160]; /* 2 lines */ - - va_start(args, fmt); - ret = vsprintf(s, fmt, args); - if (buf == NULL) { - (void) printk(s); - ret = 0; - } else { - ret = min(buflen, ret); - memcpy(buf, s, ret); - } - va_end(args); - return ret; -} #endif /* ADVANSYS_STATS */ #ifdef ADVANSYS_DEBUG @@ -4787,7 +5671,7 @@ printk( " next %x, extra_bytes %u, host_busy %u, host_no %d, last_reset %d,\n", (unsigned) s->next, s->extra_bytes, s->host_busy, s->host_no, - s->last_reset); + (unsigned) s->last_reset); printk( " host_wait %x, host_queue %x, hostt %x, block %x,\n", @@ -4807,10 +5691,8 @@ s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma, s->loaded_as_module); - printk("hostdata (struct asc_board)\n"); - asc_prt_dvc_var(&ASC_BOARD(s)->board); - asc_prt_dvc_cfg(&ASC_BOARD(s)->cfg); - printk(" overrun_buf %x\n", (unsigned) &ASC_BOARD(s)->overrun_buf[0]); + asc_prt_dvc_var(&ASC_BOARDP(s)->asc_dvc_var); + asc_prt_dvc_cfg(&ASC_BOARDP(s)->asc_dvc_cfg); } /* @@ -4851,9 +5733,8 @@ (unsigned) h->no_scam, (unsigned) h->pci_fix_asyn_xfer); printk( -" int_count %ld, req_count %ld, busy_count %ld, cfg %x, saved_ptr2func %x\n", - h->int_count, h->req_count, h->busy_count, (unsigned) h->cfg, - (unsigned) h->saved_ptr2func); +" cfg %x, saved_ptr2func %x\n", + (unsigned) h->cfg, (unsigned) h->saved_ptr2func); } /* @@ -4974,18 +5855,18 @@ break; case 1: printk(" %2.2X", - (unsigned) s[i+(j*4)+4]); + (unsigned) s[i+(j*4)]); break; case 2: printk(" %2.2X%2.2X", - (unsigned) s[i+(j*4)+4], - (unsigned) s[i+(j*4)+5]); + (unsigned) s[i+(j*4)], + (unsigned) s[i+(j*4)+1]); break; case 3: printk(" %2.2X%2.2X%2.2X", - (unsigned) s[i+(j*4)+4], - (unsigned) s[i+(j*4)+5], - (unsigned) s[i+(j*4)+6]); + (unsigned) s[i+(j*4)+1], + (unsigned) s[i+(j*4)+2], + (unsigned) s[i+(j*4)+3]); break; } @@ -5024,7 +5905,6 @@ ) { PortAddr eisa_cfg_iop; - eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) | (PortAddr) (ASC_EISA_CFG_IOP_MASK); return (inpw(eisa_cfg_iop)); @@ -5037,7 +5917,6 @@ ) { ushort cfg_lsw; - if (AscGetChipScsiID(iop_base) == new_host_id) { return (new_host_id); } @@ -5048,25 +5927,16 @@ return (AscGetChipScsiID(iop_base)); } -ushort -AscGetChipBiosAddress( - PortAddr iop_base, - ushort bus_type +uchar +AscGetChipScsiCtrl( + PortAddr iop_base ) { - ushort cfg_lsw; - ushort bios_addr; - - if ((bus_type & ASC_IS_EISA) != 0) { - cfg_lsw = AscGetEisaChipCfg(iop_base); - cfg_lsw &= 0x000F; - bios_addr = (ushort) (ASC_BIOS_MIN_ADDR + - (cfg_lsw * ASC_BIOS_BANK_SIZE)); - return (bios_addr); - } - cfg_lsw = AscGetChipCfgLsw(iop_base); - bios_addr = (ushort) (((cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE) + ASC_BIOS_MIN_ADDR); - return (bios_addr); + uchar sc; + AscSetBank(iop_base, 1); + sc = inp(iop_base + IOP_REG_SC); + AscSetBank(iop_base, 0); + return (sc); } uchar @@ -5076,10 +5946,8 @@ ) { if ((bus_type & ASC_IS_EISA) != 0) { - PortAddr eisa_iop; uchar revision; - eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) | (PortAddr) ASC_EISA_REV_IOP_MASK; revision = inp(eisa_iop); @@ -5094,17 +5962,21 @@ ) { ushort chip_ver; - chip_ver = AscGetChipVerNo(iop_base); - if ((chip_ver >= ASC_CHIP_MIN_VER_VL) && - (chip_ver <= ASC_CHIP_MAX_VER_VL)) { - if (((iop_base & 0x0C30) == 0x0C30) || - ((iop_base & 0x0C50) == 0x0C50)) { + if ( + (chip_ver >= ASC_CHIP_MIN_VER_VL) + && (chip_ver <= ASC_CHIP_MAX_VER_VL) + ) { + if ( + ((iop_base & 0x0C30) == 0x0C30) + || ((iop_base & 0x0C50) == 0x0C50) + ) { return (ASC_IS_EISA); } return (ASC_IS_VL); - } else if ((chip_ver >= ASC_CHIP_MIN_VER_ISA) && - (chip_ver <= ASC_CHIP_MAX_VER_ISA)) { + } + if ((chip_ver >= ASC_CHIP_MIN_VER_ISA) && + (chip_ver <= ASC_CHIP_MAX_VER_ISA)) { if (chip_ver >= ASC_CHIP_MIN_VER_ISA_PNP) { return (ASC_IS_ISAPNP); } @@ -5112,25 +5984,8 @@ } else if ((chip_ver >= ASC_CHIP_MIN_VER_PCI) && (chip_ver <= ASC_CHIP_MAX_VER_PCI)) { return (ASC_IS_PCI); - } else { - return (0); - } -} - -void -AscEnableIsaDma( - uchar dma_channel -) -{ - if (dma_channel < 4) { - outp(0x000B, (ushort) (0xC0 | dma_channel)); - outp(0x000A, dma_channel); - } else if (dma_channel < 8) { - - outp(0x00D6, (ushort) (0xC0 | (dma_channel - 4))); - outp(0x00D4, (ushort) (dma_channel - 4)); } - return; + return (0); } ulong @@ -5144,11 +5999,9 @@ ulong chksum; ushort mcode_word_size; ushort mcode_chksum; - mcode_word_size = (ushort) (mcode_size >> 1); AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size); AscMemWordCopyToLram(iop_base, s_addr, mcode_buf, mcode_word_size); - chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size); mcode_chksum = (ushort) AscMemSumLramWord(iop_base, (ushort) ASC_CODE_SEC_BEG, @@ -5158,12 +6011,23 @@ return (chksum); } -uchar _hextbl_[16] = -{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'A', 'B', 'C', 'D', 'E', 'F'}; +int +AscFindSignature( + PortAddr iop_base +) +{ + ushort sig_word; + if (AscGetChipSignatureByte(iop_base) == (uchar) ASC_1000_ID1B) { + sig_word = AscGetChipSignatureWord(iop_base); + if ((sig_word == (ushort) ASC_1000_ID0W) || + (sig_word == (ushort) ASC_1000_ID0W_FIX)) { + return (1); + } + } + return (0); +} uchar _isa_pnp_inited = 0; - PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] = { 0x100, ASC_IOADR_1, 0x120, ASC_IOADR_2, 0x140, ASC_IOADR_3, ASC_IOADR_4, @@ -5210,10 +6074,8 @@ PortAddr s_addr ) { - int i; PortAddr iop_base; - for (i = 0; i < ASC_IOADR_TABLE_MAX_IX; i++) { if (_asc_def_iop_base[i] > s_addr) { break; @@ -5221,6 +6083,13 @@ } for (; i < ASC_IOADR_TABLE_MAX_IX; i++) { iop_base = _asc_def_iop_base[i]; + if (check_region(iop_base, ASC_IOADR_GAP) != 0) { + ASC_DBG1(1, + "AscSearchIOPortAddr11: check_region() failed I/O port %x\n", + iop_base); + continue; + } + ASC_DBG1(1, "AscSearchIOPortAddr11: probing I/O port %x\n", iop_base); if (AscFindSignature(iop_base)) { return (iop_base); } @@ -5228,23 +6097,6 @@ return (0); } -int -AscFindSignature( - PortAddr iop_base -) -{ - ushort sig_word; - - if ((inp((PortAddr) (iop_base + 1)) & 0xFF) == (uchar) ASC_1000_ID1B) { - sig_word = inpw(iop_base); - if ((sig_word == (ushort) ASC_1000_ID0W) || - (sig_word == (ushort) ASC_1000_ID0W_FIX)) { - return (1); - } - } - return (0); -} - void AscToggleIRQAct( PortAddr iop_base @@ -5256,14 +6108,17 @@ } #if CC_INIT_INQ_DISPLAY - +uchar _hextbl_[16] = +{ + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F' +}; #endif void AscSetISAPNPWaitForKey( - void) + void) { - outp(ASC_ISA_PNP_PORT_ADDR, 0x02); outp(ASC_ISA_PNP_PORT_WRITE, 0x02); return; @@ -5277,35 +6132,34 @@ { ushort cfg_lsw; uchar chip_irq; - if ((bus_type & ASC_IS_EISA) != 0) { - cfg_lsw = AscGetEisaChipCfg(iop_base); chip_irq = (uchar) (((cfg_lsw >> 8) & 0x07) + 10); if ((chip_irq == 13) || (chip_irq > 15)) { - return (0); } return (chip_irq); - } else { - + } + if ((bus_type & ASC_IS_VL) != 0) { cfg_lsw = AscGetChipCfgLsw(iop_base); - - if ((bus_type & ASC_IS_VL) != 0) { - - chip_irq = (uchar) (((cfg_lsw >> 2) & 0x07)); - if ((chip_irq == 0) || - (chip_irq == 4) || - (chip_irq == 7)) { - return (0); - } - return ((uchar) (chip_irq + (ASC_MIN_IRQ_NO - 1))); + chip_irq = (uchar) (((cfg_lsw >> 2) & 0x07)); + if ((chip_irq == 0) || + (chip_irq == 4) || + (chip_irq == 7)) { + return (0); + } +#if CC_PLEXTOR_VL + if (chip_irq == 5) { + return (9); } - chip_irq = (uchar) (((cfg_lsw >> 2) & 0x03)); - if (chip_irq == 3) - chip_irq += (uchar) 2; - return ((uchar) (chip_irq + ASC_MIN_IRQ_NO)); +#endif + return ((uchar) (chip_irq + (ASC_MIN_IRQ_NO - 1))); } + cfg_lsw = AscGetChipCfgLsw(iop_base); + chip_irq = (uchar) (((cfg_lsw >> 2) & 0x03)); + if (chip_irq == 3) + chip_irq += (uchar) 2; + return ((uchar) (chip_irq + ASC_MIN_IRQ_NO)); } uchar @@ -5316,10 +6170,13 @@ ) { ushort cfg_lsw; - if ((bus_type & ASC_IS_VL) != 0) { - if (irq_no != 0) { +#if CC_PLEXTOR_VL + if (irq_no == 9) { + irq_no = 14; + } +#endif if ((irq_no < ASC_MIN_IRQ_NO) || (irq_no > ASC_MAX_IRQ_NO)) { irq_no = 0; } else { @@ -5330,16 +6187,13 @@ cfg_lsw |= (ushort) 0x0010; AscSetChipCfgLsw(iop_base, cfg_lsw); AscToggleIRQAct(iop_base); - cfg_lsw = (ushort) (AscGetChipCfgLsw(iop_base) & 0xFFE0); cfg_lsw |= (ushort) ((irq_no & 0x07) << 2); AscSetChipCfgLsw(iop_base, cfg_lsw); AscToggleIRQAct(iop_base); - return (AscGetChipIRQ(iop_base, bus_type)); - - } else if ((bus_type & (ASC_IS_ISA)) != 0) { - + } + if ((bus_type & (ASC_IS_ISA)) != 0) { if (irq_no == 15) irq_no -= (uchar) 2; irq_no -= (uchar) ASC_MIN_IRQ_NO; @@ -5347,30 +6201,28 @@ cfg_lsw |= (ushort) ((irq_no & 0x03) << 2); AscSetChipCfgLsw(iop_base, cfg_lsw); return (AscGetChipIRQ(iop_base, bus_type)); - } else { - - return (0); } + return (0); } -uchar -AscGetChipScsiCtrl( - PortAddr iop_base +void +AscEnableIsaDma( + uchar dma_channel ) { - uchar sc; - - AscSetBank(iop_base, 1); - sc = inp(iop_base + IOP_REG_SC); - AscSetBank(iop_base, 0); - return (sc); + if (dma_channel < 4) { + outp(0x000B, (ushort) (0xC0 | dma_channel)); + outp(0x000A, dma_channel); + } else if (dma_channel < 8) { + outp(0x00D6, (ushort) (0xC0 | (dma_channel - 4))); + outp(0x00D4, (ushort) (dma_channel - 4)); + } + return; } -extern uchar _sdtr_period_tbl_[]; - int AscIsrChipHalted( - ASC_DVC_VAR asc_ptr_type * asc_dvc + REG ASC_DVC_VAR asc_ptr_type * asc_dvc ) { SDTR_XMSG sdtr_xmsg; @@ -5384,16 +6236,14 @@ uchar tag_code; uchar q_status; uchar halt_qp; - uchar sdtr_data; + uchar sdtr_data = 0; uchar target_ix; uchar q_cntl, tid_no; uchar cur_dvc_qng; uchar asyn_sdtr; uchar scsi_status; - iop_base = asc_dvc->iop_base; int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W); - halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B); halt_q_addr = ASC_QNO_TO_QADDR(halt_qp); target_ix = AscReadLramByte(iop_base, @@ -5403,53 +6253,73 @@ tid_no = ASC_TIX_TO_TID(target_ix); target_id = (uchar) ASC_TID_TO_TARGET_ID(tid_no); if (asc_dvc->pci_fix_asyn_xfer & target_id) { - asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB; } else { asyn_sdtr = 0; } - if (int_halt_code == ASC_HALT_EXTMSG_IN) { - + if (int_halt_code == ASC_HALT_DISABLE_ASYN_USE_SYN_FIX) { + if (asc_dvc->pci_fix_asyn_xfer & target_id) { + AscSetChipSDTR(iop_base, 0, tid_no); + } + AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); + return (0); + } else if (int_halt_code == ASC_HALT_ENABLE_ASYN_USE_SYN_FIX) { + if (asc_dvc->pci_fix_asyn_xfer & target_id) { + AscSetChipSDTR(iop_base, asyn_sdtr, tid_no); + } + AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); + return (0); + } else if (int_halt_code == ASC_HALT_EXTMSG_IN) { AscMemWordCopyFromLram(iop_base, ASCV_MSGIN_BEG, (ushort dosfar *) & sdtr_xmsg, (ushort) (sizeof (SDTR_XMSG) >> 1)); - if ((sdtr_xmsg.msg_type == MS_EXTEND) && - (sdtr_xmsg.msg_len == MS_SDTR_LEN)) { + if ( + (sdtr_xmsg.msg_type == MS_EXTEND) + && (sdtr_xmsg.msg_len == MS_SDTR_LEN) + ) { sdtr_accept = TRUE; if (sdtr_xmsg.msg_req == MS_SDTR_CODE) { - if (sdtr_xmsg.req_ack_offset > ASC_SYN_MAX_OFFSET) { - + if ( + (sdtr_xmsg.req_ack_offset > ASC_SYN_MAX_OFFSET) + ) { sdtr_accept = FALSE; sdtr_xmsg.req_ack_offset = ASC_SYN_MAX_OFFSET; } - sdtr_data = AscCalSDTRData(sdtr_xmsg.xfer_period, - sdtr_xmsg.req_ack_offset); + if ( + (sdtr_xmsg.xfer_period < asc_dvc->sdtr_period_tbl[0]) + || (sdtr_xmsg.xfer_period > asc_dvc->sdtr_period_tbl[asc_dvc->max_sdtr_index]) + ) { + sdtr_accept = FALSE; + } + if (sdtr_accept) { + sdtr_data = AscCalSDTRData(asc_dvc, sdtr_xmsg.xfer_period, + sdtr_xmsg.req_ack_offset); + if ((sdtr_data == 0xFF)) { + q_cntl |= QC_MSG_OUT; + asc_dvc->init_sdtr &= ~target_id; + asc_dvc->sdtr_done &= ~target_id; + AscSetChipSDTR(iop_base, asyn_sdtr, tid_no); + } + } if (sdtr_xmsg.req_ack_offset == 0) { - q_cntl &= ~QC_MSG_OUT; asc_dvc->init_sdtr &= ~target_id; asc_dvc->sdtr_done &= ~target_id; AscSetChipSDTR(iop_base, asyn_sdtr, tid_no); - } else if ((sdtr_data == 0xFF)) { - - q_cntl |= QC_MSG_OUT; - asc_dvc->init_sdtr &= ~target_id; - asc_dvc->sdtr_done &= ~target_id; - AscSetChipSDTR(iop_base, asyn_sdtr, tid_no); } else { - if (sdtr_accept && (q_cntl & QC_MSG_OUT)) { - + if ( + sdtr_accept + && (q_cntl & QC_MSG_OUT) + ) { q_cntl &= ~QC_MSG_OUT; asc_dvc->sdtr_done |= target_id; asc_dvc->init_sdtr |= target_id; asc_dvc->pci_fix_asyn_xfer &= ~target_id; AscSetChipSDTR(iop_base, sdtr_data, tid_no); } else { - q_cntl |= QC_MSG_OUT; - - AscMsgOutSDTR(iop_base, + AscMsgOutSDTR(asc_dvc, sdtr_xmsg.xfer_period, sdtr_xmsg.req_ack_offset); asc_dvc->pci_fix_asyn_xfer &= ~target_id; @@ -5458,7 +6328,6 @@ asc_dvc->init_sdtr |= target_id; } } - AscWriteLramByte(iop_base, (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL), q_cntl); @@ -5467,62 +6336,59 @@ } } } else if (int_halt_code == ASC_HALT_CHK_CONDITION) { - q_cntl |= QC_REQ_SENSE; +#if CC_CHK_COND_REDO_SDTR if (((asc_dvc->init_sdtr & target_id) != 0) && ((asc_dvc->sdtr_done & target_id) != 0)) { - - sdtr_data = AscReadLramByte(iop_base, - (ushort) ((ushort) ASCV_SDTR_DATA_BEG + (ushort) tid_no)); - AscMsgOutSDTR(iop_base, - _sdtr_period_tbl_[(sdtr_data >> 4) & (uchar) (ASC_SYN_XFER_NO - 1)], - (uchar) (sdtr_data & (uchar) ASC_SYN_MAX_OFFSET)); + asc_dvc->sdtr_done &= ~target_id; + sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no); q_cntl |= QC_MSG_OUT; + AscMsgOutSDTR(asc_dvc, + asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) & (uchar) (ASC_SYN_XFER_NO - 1)], + (uchar) (sdtr_data & (uchar) ASC_SYN_MAX_OFFSET)); } +#endif AscWriteLramByte(iop_base, (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL), q_cntl); - tag_code = AscReadLramByte(iop_base, (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_TAG_CODE)); tag_code &= 0xDC; + if ( + (asc_dvc->pci_fix_asyn_xfer & target_id) + && !(asc_dvc->pci_fix_asyn_xfer_always & target_id) + ) { + tag_code |= (ASC_TAG_FLAG_DISABLE_DISCONNECT + | ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX); + } AscWriteLramByte(iop_base, (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_TAG_CODE), tag_code); - q_status = AscReadLramByte(iop_base, (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_STATUS)); q_status |= (QS_READY | QS_BUSY); AscWriteLramByte(iop_base, (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_STATUS), q_status); - scsi_busy = AscReadLramByte(iop_base, (ushort) ASCV_SCSIBUSY_B); scsi_busy &= ~target_id; AscWriteLramByte(iop_base, (ushort) ASCV_SCSIBUSY_B, scsi_busy); - AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); return (0); } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) { - AscMemWordCopyFromLram(iop_base, ASCV_MSGOUT_BEG, (ushort dosfar *) & out_msg, (ushort) (sizeof (SDTR_XMSG) >> 1)); - if ((out_msg.msg_type == MS_EXTEND) && (out_msg.msg_len == MS_SDTR_LEN) && (out_msg.msg_req == MS_SDTR_CODE)) { - asc_dvc->init_sdtr &= ~target_id; asc_dvc->sdtr_done &= ~target_id; AscSetChipSDTR(iop_base, asyn_sdtr, tid_no); - } else { - } - q_cntl &= ~QC_MSG_OUT; AscWriteLramByte(iop_base, (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL), @@ -5530,30 +6396,44 @@ AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); return (0); } else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) { - scsi_status = AscReadLramByte(iop_base, (ushort) ((ushort) halt_q_addr + (ushort) ASC_SCSIQ_SCSI_STATUS)); cur_dvc_qng = AscReadLramByte(iop_base, (ushort) ((ushort) ASC_QADR_BEG + (ushort) target_ix)); if ((cur_dvc_qng > 0) && (asc_dvc->cur_dvc_qng[tid_no] > 0)) { - scsi_busy = AscReadLramByte(iop_base, (ushort) ASCV_SCSIBUSY_B); scsi_busy |= target_id; AscWriteLramByte(iop_base, (ushort) ASCV_SCSIBUSY_B, scsi_busy); asc_dvc->queue_full_or_busy |= target_id; - if (scsi_status == SS_QUEUE_FULL) { if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) { cur_dvc_qng -= 1; asc_dvc->max_dvc_qng[tid_no] = cur_dvc_qng; - AscWriteLramByte(iop_base, (ushort) ((ushort) ASCV_MAX_DVC_QNG_BEG + (ushort) tid_no), cur_dvc_qng); } +#ifdef ADVANSYS_STATS + { + struct asc_board *boardp; + int i; + for (i = 0; i < ASC_NUM_BOARD_SUPPORTED; i++) { + if (asc_host[i] == NULL) { + continue; + } + boardp = ASC_BOARDP(asc_host[i]); + if (&boardp->asc_dvc_var == asc_dvc) { + boardp->asc_stats.queue_full |= target_id; + boardp->asc_stats.queue_full_cnt[tid_no] = + cur_dvc_qng; + break; + } + } + } +#endif } } AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); @@ -5566,57 +6446,52 @@ _AscCopyLramScsiDoneQ( PortAddr iop_base, ushort q_addr, - ASC_QDONE_INFO dosfar * scsiq, + REG ASC_QDONE_INFO dosfar * scsiq, ulong max_dma_count ) { ushort _val; uchar sg_queue_cnt; - DvcGetQinfo(iop_base, (ushort) (q_addr + (ushort) ASC_SCSIQ_DONE_INFO_BEG), (ushort dosfar *) scsiq, (ushort) ((sizeof (ASC_SCSIQ_2) + sizeof (ASC_SCSIQ_3)) / 2)); - #if !CC_LITTLE_ENDIAN_HOST AscAdjEndianQDoneInfo(scsiq); #endif - _val = AscReadLramWord(iop_base, (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS)); scsiq->q_status = (uchar) _val; scsiq->q_no = (uchar) (_val >> 8); - _val = AscReadLramWord(iop_base, (ushort) (q_addr + (ushort) ASC_SCSIQ_B_CNTL)); scsiq->cntl = (uchar) _val; sg_queue_cnt = (uchar) (_val >> 8); - _val = AscReadLramWord(iop_base, (ushort) (q_addr + (ushort) ASC_SCSIQ_B_SENSE_LEN)); scsiq->sense_len = (uchar) _val; - scsiq->user_def = (uchar) (_val >> 8); - + scsiq->extra_bytes = (uchar) (_val >> 8); scsiq->remain_bytes = AscReadLramDWord(iop_base, (ushort) (q_addr + (ushort) ASC_SCSIQ_DW_REMAIN_XFER_CNT)); scsiq->remain_bytes &= max_dma_count; - return (sg_queue_cnt); } int AscIsrQDone( - ASC_DVC_VAR asc_ptr_type * asc_dvc + REG ASC_DVC_VAR asc_ptr_type * asc_dvc ) { uchar next_qp; - uchar i; uchar n_q_used; uchar sg_list_qp; uchar sg_queue_cnt; + uchar q_cnt; uchar done_q_tail; - uchar tid_no; +#if CC_LINK_BUSY_Q + uchar exe_tid_no; +#endif ASC_SCSI_BIT_ID_TYPE scsi_busy; ASC_SCSI_BIT_ID_TYPE target_id; PortAddr iop_base; @@ -5624,20 +6499,14 @@ ushort sg_q_addr; uchar cur_target_qng; ASC_QDONE_INFO scsiq_buf; - ASC_QDONE_INFO dosfar *scsiq; + REG ASC_QDONE_INFO dosfar *scsiq; int false_overrun; ASC_ISR_CALLBACK asc_isr_callback; - - uchar tag_code; - #if CC_LINK_BUSY_Q ushort n_busy_q_done; - #endif - iop_base = asc_dvc->iop_base; asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback; - n_q_used = 1; scsiq = (ASC_QDONE_INFO dosfar *) & scsiq_buf; done_q_tail = (uchar) AscGetVarDoneQTail(iop_base); @@ -5645,12 +6514,9 @@ next_qp = AscReadLramByte(iop_base, (ushort) (q_addr + (ushort) ASC_SCSIQ_B_FWD)); if (next_qp != ASC_QLINK_END) { - AscPutVarDoneQTail(iop_base, next_qp); q_addr = ASC_QNO_TO_QADDR(next_qp); - sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq, asc_dvc->max_dma_count); - AscWriteLramByte(iop_base, (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS), (uchar) (scsiq->q_status & (uchar) ~ (QS_READY | QS_ABORTED))); @@ -5659,7 +6525,7 @@ if ((scsiq->cntl & QC_SG_HEAD) != 0) { sg_q_addr = q_addr; sg_list_qp = next_qp; - for (i = 0; i < sg_queue_cnt; i++) { + for (q_cnt = 0; q_cnt < sg_queue_cnt; q_cnt++) { sg_list_qp = AscReadLramByte(iop_base, (ushort) (sg_q_addr + (ushort) ASC_SCSIQ_B_FWD)); sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp); @@ -5673,12 +6539,10 @@ (ushort) (sg_q_addr + (ushort) ASC_SCSIQ_B_STATUS), QS_FREE); } - n_q_used = sg_queue_cnt + 1; AscPutVarDoneQTail(iop_base, sg_list_qp); } if (asc_dvc->queue_full_or_busy & target_id) { - cur_target_qng = AscReadLramByte(iop_base, (ushort) ((ushort) ASC_QADR_BEG + (ushort) scsiq->d2.target_ix)); if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) { @@ -5700,37 +6564,31 @@ scsiq->d3.done_stat = QD_WITH_ERROR; goto FATAL_ERR_QDONE; } - if ((scsiq->d2.srb_ptr == 0UL) || ((scsiq->q_status & QS_ABORTED) != 0)) { - return (0x11); } else if (scsiq->q_status == QS_DONE) { - false_overrun = FALSE; - - if (asc_dvc->bug_fix_cntl) { - if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ADD_ONE_BYTE) { - tag_code = AscReadLramByte(iop_base, - (ushort) (q_addr + (ushort) ASC_SCSIQ_B_TAG_CODE)); - if (tag_code & ASC_TAG_FLAG_ADD_ONE_BYTE) { - if (scsiq->remain_bytes != 0UL) { - scsiq->remain_bytes--; - if (scsiq->remain_bytes == 0UL) { - false_overrun = TRUE; - } - } - } - } + if (scsiq->extra_bytes != 0) { + scsiq->remain_bytes += (ulong) scsiq->extra_bytes; } - if ((scsiq->d3.done_stat == QD_WITH_ERROR) && - (scsiq->d3.host_stat == QHSTA_M_DATA_OVER_RUN)) { - if ((scsiq->cntl & (QC_DATA_IN | QC_DATA_OUT)) == 0) { - scsiq->d3.done_stat = QD_NO_ERROR; - scsiq->d3.host_stat = QHSTA_NO_ERROR; - } else if (false_overrun) { - scsiq->d3.done_stat = QD_NO_ERROR; - scsiq->d3.host_stat = QHSTA_NO_ERROR; + if (scsiq->d3.done_stat == QD_WITH_ERROR) { + if (scsiq->d3.host_stat == QHSTA_M_DATA_OVER_RUN) { + if ((scsiq->cntl & (QC_DATA_IN | QC_DATA_OUT)) == 0) { + scsiq->d3.done_stat = QD_NO_ERROR; + scsiq->d3.host_stat = QHSTA_NO_ERROR; + } else if (false_overrun) { + scsiq->d3.done_stat = QD_NO_ERROR; + scsiq->d3.host_stat = QHSTA_NO_ERROR; + } + } else if (scsiq->d3.host_stat == QHSTA_M_HUNG_REQ_SCSI_BUS_RESET) { + AscStopChip(iop_base); + AscSetChipControl(iop_base, (uchar) (CC_SCSI_RESET | CC_HALT)); + DvcDelayNanoSecond(asc_dvc, 30000); + AscSetChipControl(iop_base, CC_HALT); + AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT); + AscSetChipStatus(iop_base, 0); + AscSetChipControl(iop_base, 0); } } #if CC_CLEAR_LRAM_SRB_PTR @@ -5738,46 +6596,39 @@ (ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR), asc_dvc->int_count); #endif - if ((scsiq->cntl & QC_NO_CALLBACK) == 0) { (*asc_isr_callback) (asc_dvc, scsiq); } else { if ((AscReadLramByte(iop_base, (ushort) (q_addr + (ushort) ASC_SCSIQ_CDB_BEG)) == SCSICMD_StartStopUnit)) { - asc_dvc->unit_not_ready &= ~target_id; if (scsiq->d3.done_stat != QD_NO_ERROR) { asc_dvc->start_motor &= ~target_id; } } } - #if CC_LINK_BUSY_Q n_busy_q_done = AscIsrExeBusyQueue(asc_dvc, tid_no); if (n_busy_q_done == 0) { - - i = tid_no + 1; + exe_tid_no = (uint) tid_no + 1; while (TRUE) { - if (i > ASC_MAX_TID) - i = 0; - if (i == tid_no) + if (exe_tid_no > ASC_MAX_TID) + exe_tid_no = 0; + if (exe_tid_no == (uint) tid_no) break; - n_busy_q_done = AscIsrExeBusyQueue(asc_dvc, i); + n_busy_q_done = AscIsrExeBusyQueue(asc_dvc, exe_tid_no); if (n_busy_q_done != 0) break; - i++; + exe_tid_no++; } } if (n_busy_q_done == 0xFFFF) return (0x80); #endif - return (1); } else { - AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS); - FATAL_ERR_QDONE: if ((scsiq->cntl & QC_NO_CALLBACK) == 0) { (*asc_isr_callback) (asc_dvc, scsiq); @@ -5788,9 +6639,12 @@ return (0); } +#if CC_LINK_BUSY_Q +#endif + int AscISR( - ASC_DVC_VAR asc_ptr_type * asc_dvc + REG ASC_DVC_VAR asc_ptr_type * asc_dvc ) { ASC_CS_TYPE chipstat; @@ -5801,15 +6655,11 @@ int int_pending; int status; uchar host_flag; - iop_base = asc_dvc->iop_base; int_pending = FALSE; - - asc_dvc->int_count++; - - if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0) || - (asc_dvc->isr_callback == 0)) { - + if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0) + || (asc_dvc->isr_callback == 0) + ) { return (ERR); } if (asc_dvc->in_critical_cnt != 0) { @@ -5818,42 +6668,54 @@ } if (asc_dvc->is_in_int) { AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY); - asc_dvc->busy_count++; return (ERR); } asc_dvc->is_in_int = TRUE; ctrl_reg = AscGetChipControl(iop_base); saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET | CC_SINGLE_STEP | CC_DIAG | CC_TEST)); - - if ((chipstat = AscGetChipStatus(iop_base)) & CSW_INT_PENDING) { - int_pending = TRUE; + chipstat = AscGetChipStatus(iop_base); + if (chipstat & CSW_SCSI_RESET_LATCH) { + if ( + !(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA)) + ) { + int_pending = TRUE; + asc_dvc->sdtr_done = 0; + saved_ctrl_reg &= (uchar) (~CC_HALT); + while (AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) ; + AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT)); + AscSetChipControl(iop_base, CC_HALT); + AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT); + AscSetChipStatus(iop_base, 0); + chipstat = AscGetChipStatus(iop_base); + } + } + saved_ram_addr = AscGetChipLramAddr(iop_base); + host_flag = AscReadLramByte(iop_base, ASCV_HOST_FLAG_B) & (uchar) (~ASC_HOST_FLAG_IN_ISR); + AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, + (uchar) (host_flag | (uchar) ASC_HOST_FLAG_IN_ISR)); +#if CC_ASCISR_CHECK_INT_PENDING + if ((chipstat & CSW_INT_PENDING) + || (int_pending) + ) { AscAckInterrupt(iop_base); - - host_flag = AscReadLramByte(iop_base, ASCV_HOST_FLAG_B); - AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, - (uchar) (host_flag | (uchar) ASC_HOST_FLAG_IN_ISR)); - saved_ram_addr = AscGetChipLramAddr(iop_base); - +#endif + int_pending = TRUE; if ((chipstat & CSW_HALTED) && (ctrl_reg & CC_SINGLE_STEP)) { if (AscIsrChipHalted(asc_dvc) == ERR) { - goto ISR_REPORT_QDONE_FATAL_ERROR; - } else { - saved_ctrl_reg &= ~CC_HALT; + saved_ctrl_reg &= (uchar) (~CC_HALT); } } else { ISR_REPORT_QDONE_FATAL_ERROR: if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) { while (((status = AscIsrQDone(asc_dvc)) & 0x01) != 0) { - } } else { do { if ((status = AscIsrQDone(asc_dvc)) == 1) { - break; } } while (status == 0x11); @@ -5861,12 +6723,11 @@ if ((status & 0x80) != 0) int_pending = ERR; } - AscSetChipLramAddr(iop_base, saved_ram_addr); - if (AscGetChipLramAddr(iop_base) != saved_ram_addr) { - AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SET_LRAM_ADDR); - } - AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag); +#if CC_ASCISR_CHECK_INT_PENDING } +#endif + AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag); + AscSetChipLramAddr(iop_base, saved_ram_addr); AscSetChipControl(iop_base, saved_ctrl_reg); asc_dvc->is_in_int = FALSE; return (int_pending); @@ -5874,32 +6735,29 @@ int AscScsiSetupCmdQ( - ASC_DVC_VAR asc_ptr_type * asc_dvc, - ASC_SCSI_REQ_Q dosfar * scsiq, + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_REQ_Q dosfar * scsiq, uchar dosfar * buf_addr, ulong buf_len ) { ulong phy_addr; - scsiq->r1.cntl = 0; scsiq->r1.sg_queue_cnt = 0; scsiq->r1.q_no = 0; - scsiq->r1.user_def = 0; - scsiq->cdbptr = (uchar dosfar *) scsiq->cdb; + scsiq->r1.extra_bytes = 0; scsiq->r3.scsi_stat = 0; scsiq->r3.scsi_msg = 0; scsiq->r3.host_stat = 0; scsiq->r3.done_stat = 0; scsiq->r2.vm_id = 0; + scsiq->cdbptr = (uchar dosfar *) scsiq->cdb; scsiq->r1.data_cnt = buf_len; - scsiq->r2.tag_code = (uchar) M2_QTAG_MSG_SIMPLE; scsiq->r2.flag = (uchar) ASC_FLAG_SCSIQ_REQ; scsiq->r2.srb_ptr = (ulong) scsiq; scsiq->r1.status = (uchar) QS_READY; scsiq->r1.data_addr = 0L; - if (buf_len != 0L) { if ((phy_addr = AscGetOnePhyAddr(asc_dvc, (uchar dosfar *) buf_addr, scsiq->r1.data_cnt)) == 0L) { @@ -5916,180 +6774,202 @@ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xDD, 0x0A, 0x01, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xC4, 0x0C, 0x08, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x23, 0x00, 0x16, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA4, 0x88, 0x00, 0x00, 0x00, 0x00, - 0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC8, 0x00, 0x80, 0x73, 0x03, 0x23, 0x36, 0x40, - 0xB6, 0x00, 0x36, 0x00, 0x06, 0xD6, 0x0D, 0xD2, 0x15, 0xDE, 0x12, 0xDA, 0x00, 0xA2, 0xC8, 0x00, - 0x92, 0x80, 0xE0, 0x97, 0x50, 0x00, 0xF5, 0x00, 0x0A, 0x98, 0xDF, 0x23, 0x36, 0x60, 0xB6, 0x00, - 0x92, 0x80, 0x4F, 0x00, 0xF5, 0x00, 0x0A, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, - 0x80, 0x62, 0x92, 0x80, 0x00, 0x62, 0x92, 0x80, 0x00, 0x46, 0x17, 0xEE, 0x13, 0xEA, 0x02, 0x01, - 0x09, 0xD8, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xDC, 0x00, 0x68, 0x97, 0x7F, 0x23, 0x04, 0x61, - 0x84, 0x01, 0xB2, 0x84, 0xCF, 0xC1, 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xE8, 0x01, - 0x68, 0x97, 0xD4, 0x81, 0x00, 0x33, 0x02, 0x00, 0x82, 0x88, 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, - 0x01, 0xA1, 0x08, 0x01, 0x4F, 0x00, 0x46, 0x97, 0x07, 0xA6, 0x12, 0x01, 0x00, 0x33, 0x03, 0x00, - 0x82, 0x88, 0x03, 0x03, 0x03, 0xDE, 0x00, 0x33, 0x05, 0x00, 0x82, 0x88, 0xCE, 0x00, 0x69, 0x60, - 0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x86, 0x01, 0x80, 0x63, 0x07, 0xA6, 0x32, 0x01, - 0x86, 0x81, 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6, 0x42, 0x01, 0x00, 0x33, 0x04, 0x00, - 0x82, 0x88, 0x03, 0x07, 0x02, 0x01, 0x04, 0xCA, 0x0D, 0x23, 0x2A, 0x98, 0x4D, 0x04, 0xD0, 0x84, - 0x05, 0xD8, 0x0D, 0x23, 0x2A, 0x98, 0xCD, 0x04, 0x15, 0x23, 0xB8, 0x88, 0xFB, 0x23, 0x02, 0x61, - 0x82, 0x01, 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x70, 0x01, 0x00, 0x33, 0x0A, 0x00, 0x82, 0x88, - 0x4E, 0x00, 0x07, 0xA3, 0x7C, 0x01, 0x00, 0x33, 0x0B, 0x00, 0x82, 0x88, 0xCD, 0x04, 0x36, 0x2D, - 0x00, 0x33, 0x1A, 0x00, 0x82, 0x88, 0x50, 0x04, 0x96, 0x81, 0x06, 0xAB, 0x90, 0x01, 0x96, 0x81, - 0x4E, 0x00, 0x07, 0xA3, 0xA0, 0x01, 0x50, 0x00, 0x00, 0xA3, 0x4A, 0x01, 0x00, 0x05, 0x8A, 0x81, - 0x08, 0x97, 0x02, 0x01, 0x05, 0xC6, 0x04, 0x23, 0xA0, 0x01, 0x15, 0x23, 0xA1, 0x01, 0xCC, 0x81, - 0xFD, 0x23, 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xC2, 0x01, - 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00, 0x82, 0x88, 0x06, 0x23, 0x2A, 0x98, - 0xCD, 0x04, 0xB2, 0x84, 0x06, 0x01, 0x00, 0xA2, 0xE2, 0x01, 0x57, 0x60, 0x00, 0xA0, 0xE8, 0x01, - 0xB2, 0x84, 0x80, 0x23, 0xA0, 0x01, 0xB2, 0x84, 0x80, 0x73, 0x4B, 0x00, 0x06, 0x61, 0x00, 0xA2, - 0x10, 0x02, 0x04, 0x01, 0x0D, 0xDE, 0x02, 0x01, 0x03, 0xCC, 0x4F, 0x00, 0x46, 0x97, 0x0A, 0x82, - 0x08, 0x23, 0x02, 0x41, 0x82, 0x01, 0x4F, 0x00, 0x24, 0x97, 0x48, 0x04, 0xFF, 0x23, 0x84, 0x80, - 0xB2, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00, 0x81, 0x73, 0x06, 0x29, - 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x66, 0xEB, 0x11, 0x23, 0xB8, 0x88, 0xC6, 0x97, 0xFA, 0x80, - 0x80, 0x73, 0x80, 0x77, 0x06, 0xA6, 0x3E, 0x02, 0x00, 0x33, 0x31, 0x00, 0x82, 0x88, 0x04, 0x01, - 0x03, 0xD8, 0x74, 0x98, 0x02, 0x96, 0x50, 0x82, 0xA2, 0x95, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, - 0xB6, 0x2D, 0x02, 0xA6, 0x7A, 0x02, 0x07, 0xA6, 0x68, 0x02, 0x06, 0xA6, 0x6C, 0x02, 0x03, 0xA6, - 0x70, 0x02, 0x00, 0x33, 0x10, 0x00, 0x82, 0x88, 0x4A, 0x95, 0x52, 0x82, 0xF8, 0x95, 0x52, 0x82, - 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x16, 0x84, 0x04, 0x01, 0x0C, 0xDC, 0xE0, 0x23, - 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01, 0x6F, 0x00, 0xA5, 0x01, 0x03, 0x23, - 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, 0x1C, 0x01, 0x02, 0xA6, 0xAC, 0x02, 0x07, 0xA6, - 0x68, 0x02, 0x06, 0xA6, 0x6C, 0x02, 0x00, 0x33, 0x12, 0x00, 0x82, 0x88, 0x00, 0x0E, 0x80, 0x63, - 0x00, 0x43, 0x00, 0xA0, 0x9A, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23, 0x04, 0x61, - 0x84, 0x01, 0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, - 0xEC, 0x82, 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE4, 0x02, 0x04, 0x01, 0x8E, 0xC8, 0x00, 0x33, - 0x1F, 0x00, 0x82, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x40, 0x98, 0xB6, 0x2D, - 0x01, 0xA6, 0x0E, 0x03, 0x00, 0xA6, 0x1C, 0x03, 0x07, 0xA6, 0x2A, 0x03, 0x06, 0xA6, 0x2E, 0x03, - 0x03, 0xA6, 0xFA, 0x03, 0x02, 0xA6, 0x7A, 0x02, 0x00, 0x33, 0x33, 0x00, 0x82, 0x88, 0x08, 0x23, - 0xB3, 0x01, 0x04, 0x01, 0x0E, 0xD0, 0x00, 0x33, 0x14, 0x00, 0x82, 0x88, 0x10, 0x23, 0xB3, 0x01, - 0x04, 0x01, 0x07, 0xCC, 0x00, 0x33, 0x15, 0x00, 0x82, 0x88, 0x4A, 0x95, 0xF0, 0x82, 0xF8, 0x95, - 0xF0, 0x82, 0x44, 0x98, 0x80, 0x42, 0x40, 0x98, 0x48, 0xE4, 0x04, 0x01, 0x29, 0xC8, 0x31, 0x05, - 0x07, 0x01, 0x00, 0xA2, 0x72, 0x03, 0x00, 0x43, 0x87, 0x01, 0x05, 0x05, 0x48, 0x98, 0x40, 0x98, - 0x00, 0xA6, 0x34, 0x03, 0x07, 0xA6, 0x6A, 0x03, 0x03, 0xA6, 0x16, 0x04, 0x06, 0xA6, 0x6E, 0x03, - 0x01, 0xA6, 0x34, 0x03, 0x00, 0x33, 0x25, 0x00, 0x82, 0x88, 0x4A, 0x95, 0x50, 0x83, 0xF8, 0x95, - 0x50, 0x83, 0x04, 0x01, 0x0C, 0xCE, 0x03, 0xC8, 0x00, 0x33, 0x42, 0x00, 0x82, 0x88, 0x00, 0x01, - 0x05, 0x05, 0xFF, 0xA2, 0x90, 0x03, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x4C, 0x83, 0x05, 0x05, - 0x01, 0xA6, 0x9A, 0x03, 0x00, 0xA6, 0xAA, 0x03, 0xF0, 0x83, 0x68, 0x98, 0x80, 0x42, 0x01, 0xA6, - 0x9A, 0x03, 0xBA, 0x83, 0x00, 0x33, 0x2F, 0x00, 0x82, 0x88, 0x68, 0x98, 0x80, 0x42, 0x00, 0xA6, - 0xAA, 0x03, 0xBA, 0x83, 0x00, 0x33, 0x26, 0x00, 0x82, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, - 0x04, 0x23, 0xA0, 0x01, 0x12, 0x23, 0xA1, 0x01, 0xF0, 0x83, 0x04, 0xF0, 0x80, 0x6B, 0x00, 0x33, - 0x20, 0x00, 0x82, 0x88, 0x03, 0xA6, 0xEE, 0x03, 0x07, 0xA6, 0xE6, 0x03, 0x06, 0xA6, 0xEA, 0x03, - 0x00, 0x33, 0x17, 0x00, 0x82, 0x88, 0x4A, 0x95, 0xD4, 0x83, 0xF8, 0x95, 0xD4, 0x83, 0xFA, 0x83, - 0x04, 0xF0, 0x80, 0x6B, 0x00, 0x33, 0x20, 0x00, 0x82, 0x88, 0xB6, 0x2D, 0x03, 0xA6, 0x16, 0x04, - 0x07, 0xA6, 0x0E, 0x04, 0x06, 0xA6, 0x12, 0x04, 0x00, 0x33, 0x30, 0x00, 0x82, 0x88, 0x4A, 0x95, - 0xFA, 0x83, 0xF8, 0x95, 0xFA, 0x83, 0xA2, 0x0D, 0x80, 0x63, 0x07, 0xA6, 0x24, 0x04, 0x00, 0x33, - 0x18, 0x00, 0x82, 0x88, 0x03, 0x03, 0x80, 0x63, 0xA3, 0x01, 0x07, 0xA4, 0x2E, 0x04, 0x23, 0x01, - 0x00, 0xA2, 0x50, 0x04, 0x0A, 0xA0, 0x40, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1D, 0x00, 0x82, 0x88, - 0x0B, 0xA0, 0x4C, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1E, 0x00, 0x82, 0x88, 0x42, 0x23, 0xB8, 0x88, - 0x00, 0x23, 0x22, 0xA3, 0xB2, 0x04, 0x08, 0x23, 0x22, 0xA3, 0x6C, 0x04, 0x28, 0x23, 0x22, 0xA3, - 0x78, 0x04, 0x02, 0x23, 0x22, 0xA3, 0x8E, 0x04, 0x42, 0x23, 0xB8, 0x88, 0x4A, 0x00, 0x06, 0x61, - 0x00, 0xA0, 0x78, 0x04, 0x45, 0x23, 0xB8, 0x88, 0xC6, 0x97, 0x00, 0xA2, 0x8A, 0x04, 0x74, 0x98, - 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20, 0x81, 0x62, 0xF6, 0x81, 0x47, 0x23, 0xB8, 0x88, 0x04, 0x01, - 0x0C, 0xDE, 0x14, 0x01, 0x00, 0xA2, 0xA6, 0x04, 0xC6, 0x97, 0x74, 0x98, 0x00, 0x33, 0x00, 0x81, - 0xC0, 0x20, 0x81, 0x62, 0x10, 0x82, 0x43, 0x23, 0xB8, 0x88, 0x04, 0x23, 0xA0, 0x01, 0x44, 0x23, - 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3, 0xC0, 0x04, 0x00, 0x33, 0x27, 0x00, 0x82, 0x88, - 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xC6, 0x97, 0xF4, 0x94, - 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00, 0x00, 0xA3, 0xEE, 0x04, 0x00, 0x05, 0x76, 0x00, - 0x06, 0x61, 0x00, 0xA2, 0xE8, 0x04, 0xD6, 0x84, 0x08, 0x97, 0xCD, 0x04, 0xF2, 0x84, 0x48, 0x04, - 0xFF, 0x23, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23, 0x82, 0x01, 0x02, 0x85, 0x02, 0x23, - 0xA0, 0x01, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x0E, 0x05, 0x1D, 0x01, 0x04, 0xD6, 0xFF, 0x23, + 0x00, 0x00, 0x00, 0x23, 0x00, 0x20, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x88, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC6, 0x00, 0x80, 0x73, 0x03, 0x23, 0x36, 0x40, + 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2, 0xC6, 0x00, 0x92, 0x80, + 0x20, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x4A, 0x98, 0xDF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, + 0x4F, 0x00, 0xF5, 0x00, 0x4A, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, 0x80, 0x62, + 0x92, 0x80, 0x00, 0x62, 0x92, 0x80, 0x00, 0x46, 0x17, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8, + 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xDA, 0x00, 0xA8, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01, + 0xD2, 0x84, 0xD0, 0xC1, 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xE6, 0x01, 0xA8, 0x97, + 0xD2, 0x81, 0x00, 0x33, 0x02, 0x00, 0xC2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, + 0x06, 0x01, 0x4F, 0x00, 0x86, 0x97, 0x07, 0xA6, 0x10, 0x01, 0x00, 0x33, 0x03, 0x00, 0xC2, 0x88, + 0x03, 0x03, 0x03, 0xDE, 0x00, 0x33, 0x05, 0x00, 0xC2, 0x88, 0xCE, 0x00, 0x69, 0x60, 0xCE, 0x00, + 0x02, 0x03, 0x4A, 0x60, 0x00, 0xA2, 0x84, 0x01, 0x80, 0x63, 0x07, 0xA6, 0x30, 0x01, 0x84, 0x81, + 0x03, 0x03, 0x80, 0x63, 0xE2, 0x00, 0x07, 0xA6, 0x40, 0x01, 0x00, 0x33, 0x04, 0x00, 0xC2, 0x88, + 0x03, 0x07, 0x02, 0x01, 0x04, 0xCA, 0x0D, 0x23, 0x6A, 0x98, 0x4D, 0x04, 0xF0, 0x84, 0x05, 0xD8, + 0x0D, 0x23, 0x6A, 0x98, 0xCD, 0x04, 0x15, 0x23, 0xF8, 0x88, 0xFB, 0x23, 0x02, 0x61, 0x82, 0x01, + 0x80, 0x63, 0x02, 0x03, 0x06, 0xA3, 0x6E, 0x01, 0x00, 0x33, 0x0A, 0x00, 0xC2, 0x88, 0x4E, 0x00, + 0x07, 0xA3, 0x7A, 0x01, 0x00, 0x33, 0x0B, 0x00, 0xC2, 0x88, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, + 0x1A, 0x00, 0xC2, 0x88, 0x50, 0x04, 0x94, 0x81, 0x06, 0xAB, 0x8E, 0x01, 0x94, 0x81, 0x4E, 0x00, + 0x07, 0xA3, 0x9E, 0x01, 0x50, 0x00, 0x00, 0xA3, 0x48, 0x01, 0x00, 0x05, 0x88, 0x81, 0x48, 0x97, + 0x02, 0x01, 0x05, 0xC6, 0x04, 0x23, 0xA0, 0x01, 0x15, 0x23, 0xA1, 0x01, 0xCA, 0x81, 0xFD, 0x23, + 0x02, 0x61, 0x82, 0x01, 0x0A, 0xDA, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xC0, 0x01, 0x80, 0x63, + 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1B, 0x00, 0xC2, 0x88, 0x06, 0x23, 0x6A, 0x98, 0xCD, 0x04, + 0xD2, 0x84, 0x06, 0x01, 0x00, 0xA2, 0xE0, 0x01, 0x57, 0x60, 0x00, 0xA0, 0xE6, 0x01, 0xD2, 0x84, + 0x80, 0x23, 0xA0, 0x01, 0xD2, 0x84, 0x80, 0x73, 0x4B, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x0E, 0x02, + 0x04, 0x01, 0x0D, 0xDE, 0x02, 0x01, 0x03, 0xCC, 0x4F, 0x00, 0x86, 0x97, 0x08, 0x82, 0x08, 0x23, + 0x02, 0x41, 0x82, 0x01, 0x4F, 0x00, 0x64, 0x97, 0x48, 0x04, 0xFF, 0x23, 0x84, 0x80, 0xF2, 0x97, + 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0, 0x01, 0x23, 0xE8, 0x00, 0x81, 0x73, 0x06, 0x29, 0x03, 0x42, + 0x06, 0xE2, 0x03, 0xEE, 0x66, 0xEB, 0x11, 0x23, 0xF8, 0x88, 0x06, 0x98, 0xF8, 0x80, 0x80, 0x73, + 0x80, 0x77, 0x06, 0xA6, 0x3C, 0x02, 0x00, 0x33, 0x31, 0x00, 0xC2, 0x88, 0x04, 0x01, 0x03, 0xD8, + 0xB4, 0x98, 0x3E, 0x96, 0x4E, 0x82, 0xCE, 0x95, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, + 0x02, 0xA6, 0x78, 0x02, 0x07, 0xA6, 0x66, 0x02, 0x06, 0xA6, 0x6A, 0x02, 0x03, 0xA6, 0x6E, 0x02, + 0x00, 0x33, 0x10, 0x00, 0xC2, 0x88, 0x6A, 0x95, 0x50, 0x82, 0x34, 0x96, 0x50, 0x82, 0x04, 0x23, + 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01, 0x28, 0x84, 0x04, 0x01, 0x0C, 0xDC, 0xE0, 0x23, 0x25, 0x61, + 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04, 0xA8, 0x01, 0x6F, 0x00, 0xA5, 0x01, 0x03, 0x23, 0xA4, 0x01, + 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B, 0x1C, 0x01, 0x02, 0xA6, 0xAA, 0x02, 0x07, 0xA6, 0x66, 0x02, + 0x06, 0xA6, 0x6A, 0x02, 0x00, 0x33, 0x12, 0x00, 0xC2, 0x88, 0x00, 0x0E, 0x80, 0x63, 0x00, 0x43, + 0x00, 0xA0, 0x98, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC, 0xE7, 0x23, 0x04, 0x61, 0x84, 0x01, + 0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0xEA, 0x82, + 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE2, 0x02, 0x04, 0x01, 0x98, 0xC8, 0x00, 0x33, 0x1F, 0x00, + 0xC2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D, 0x80, 0x98, 0xB6, 0x2D, 0x01, 0xA6, + 0x14, 0x03, 0x00, 0xA6, 0x14, 0x03, 0x07, 0xA6, 0x0C, 0x03, 0x06, 0xA6, 0x10, 0x03, 0x03, 0xA6, + 0x0C, 0x04, 0x02, 0xA6, 0x78, 0x02, 0x00, 0x33, 0x33, 0x00, 0xC2, 0x88, 0x6A, 0x95, 0xEE, 0x82, + 0x34, 0x96, 0xEE, 0x82, 0x84, 0x98, 0x80, 0x42, 0x80, 0x98, 0x60, 0xE4, 0x04, 0x01, 0x29, 0xC8, + 0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x54, 0x03, 0x00, 0x43, 0x87, 0x01, 0x05, 0x05, 0x88, 0x98, + 0x80, 0x98, 0x00, 0xA6, 0x16, 0x03, 0x07, 0xA6, 0x4C, 0x03, 0x03, 0xA6, 0x28, 0x04, 0x06, 0xA6, + 0x50, 0x03, 0x01, 0xA6, 0x16, 0x03, 0x00, 0x33, 0x25, 0x00, 0xC2, 0x88, 0x6A, 0x95, 0x32, 0x83, + 0x34, 0x96, 0x32, 0x83, 0x04, 0x01, 0x0C, 0xCE, 0x03, 0xC8, 0x00, 0x33, 0x42, 0x00, 0xC2, 0x88, + 0x00, 0x01, 0x05, 0x05, 0xFF, 0xA2, 0x72, 0x03, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x2E, 0x83, + 0x05, 0x05, 0x15, 0x01, 0x00, 0xA2, 0x92, 0x03, 0xEC, 0x00, 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, + 0x00, 0x3F, 0x00, 0x00, 0x01, 0xA6, 0x8E, 0x03, 0x00, 0xA6, 0x8E, 0x03, 0x02, 0x84, 0x80, 0x42, + 0x80, 0x98, 0x01, 0xA6, 0x9C, 0x03, 0x00, 0xA6, 0xB4, 0x03, 0x02, 0x84, 0xA8, 0x98, 0x80, 0x42, + 0x01, 0xA6, 0x9C, 0x03, 0x07, 0xA6, 0xAA, 0x03, 0xCC, 0x83, 0x6A, 0x95, 0xA0, 0x83, 0x00, 0x33, + 0x2F, 0x00, 0xC2, 0x88, 0xA8, 0x98, 0x80, 0x42, 0x00, 0xA6, 0xB4, 0x03, 0x07, 0xA6, 0xC2, 0x03, + 0xCC, 0x83, 0x6A, 0x95, 0xB8, 0x83, 0x00, 0x33, 0x26, 0x00, 0xC2, 0x88, 0x38, 0x2B, 0x80, 0x32, + 0x80, 0x36, 0x04, 0x23, 0xA0, 0x01, 0x12, 0x23, 0xA1, 0x01, 0x02, 0x84, 0x04, 0xF0, 0x80, 0x6B, + 0x00, 0x33, 0x20, 0x00, 0xC2, 0x88, 0x03, 0xA6, 0x00, 0x04, 0x07, 0xA6, 0xF8, 0x03, 0x06, 0xA6, + 0xFC, 0x03, 0x00, 0x33, 0x17, 0x00, 0xC2, 0x88, 0x6A, 0x95, 0xE6, 0x83, 0x34, 0x96, 0xE6, 0x83, + 0x0C, 0x84, 0x04, 0xF0, 0x80, 0x6B, 0x00, 0x33, 0x20, 0x00, 0xC2, 0x88, 0xB6, 0x2D, 0x03, 0xA6, + 0x28, 0x04, 0x07, 0xA6, 0x20, 0x04, 0x06, 0xA6, 0x24, 0x04, 0x00, 0x33, 0x30, 0x00, 0xC2, 0x88, + 0x6A, 0x95, 0x0C, 0x84, 0x34, 0x96, 0x0C, 0x84, 0x1D, 0x01, 0x06, 0xCC, 0x00, 0x33, 0x00, 0x84, + 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62, 0xA2, 0x0D, 0x80, 0x63, 0x07, 0xA6, 0x46, 0x04, + 0x00, 0x33, 0x18, 0x00, 0xC2, 0x88, 0x03, 0x03, 0x80, 0x63, 0xA3, 0x01, 0x07, 0xA4, 0x50, 0x04, + 0x23, 0x01, 0x00, 0xA2, 0x72, 0x04, 0x0A, 0xA0, 0x62, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1D, 0x00, + 0xC2, 0x88, 0x0B, 0xA0, 0x6E, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1E, 0x00, 0xC2, 0x88, 0x42, 0x23, + 0xF8, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xD2, 0x04, 0x08, 0x23, 0x22, 0xA3, 0x8E, 0x04, 0x28, 0x23, + 0x22, 0xA3, 0x9A, 0x04, 0x02, 0x23, 0x22, 0xA3, 0xB0, 0x04, 0x42, 0x23, 0xF8, 0x88, 0x4A, 0x00, + 0x06, 0x61, 0x00, 0xA0, 0x9A, 0x04, 0x45, 0x23, 0xF8, 0x88, 0x06, 0x98, 0x00, 0xA2, 0xAC, 0x04, + 0xB4, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20, 0x81, 0x62, 0xF4, 0x81, 0x47, 0x23, 0xF8, 0x88, + 0x04, 0x01, 0x0B, 0xDE, 0x06, 0x98, 0xB4, 0x98, 0x00, 0x33, 0x00, 0x81, 0xC0, 0x20, 0x81, 0x62, + 0x14, 0x01, 0x00, 0xA0, 0x0E, 0x02, 0x43, 0x23, 0xF8, 0x88, 0x04, 0x23, 0xA0, 0x01, 0x44, 0x23, + 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3, 0xE0, 0x04, 0x00, 0x33, 0x27, 0x00, 0xC2, 0x88, + 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01, 0x04, 0x23, 0xA0, 0x01, 0x06, 0x98, 0x14, 0x95, + 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00, 0x00, 0xA3, 0x0E, 0x05, 0x00, 0x05, 0x76, 0x00, + 0x06, 0x61, 0x00, 0xA2, 0x08, 0x05, 0xF6, 0x84, 0x48, 0x97, 0xCD, 0x04, 0x12, 0x85, 0x48, 0x04, + 0xFF, 0x23, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23, 0x82, 0x01, 0x22, 0x85, 0x02, 0x23, + 0xA0, 0x01, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x2E, 0x05, 0x1D, 0x01, 0x04, 0xD6, 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01, 0x49, 0x00, 0x81, 0x01, 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01, 0x49, 0x04, 0x80, 0x01, 0xC9, 0x00, - 0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x2E, 0x05, 0x77, 0x04, 0x01, 0x23, 0xEA, 0x00, 0x5D, 0x00, - 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63, 0x07, 0xA4, 0xA0, 0x05, 0x03, 0x03, - 0x02, 0xA0, 0x5C, 0x05, 0x9C, 0x85, 0x00, 0x33, 0x2D, 0x00, 0x82, 0x88, 0x04, 0xA0, 0x82, 0x05, - 0x80, 0x63, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x6E, 0x05, 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, - 0x02, 0x41, 0x82, 0x01, 0x50, 0x00, 0x24, 0x97, 0xD0, 0x84, 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, - 0xD0, 0x84, 0x08, 0xA0, 0x88, 0x05, 0x9C, 0x85, 0x03, 0xA0, 0x8E, 0x05, 0x9C, 0x85, 0x01, 0xA0, - 0x9A, 0x05, 0x88, 0x00, 0x80, 0x63, 0x78, 0x96, 0x4A, 0x85, 0x88, 0x86, 0x80, 0x63, 0x4A, 0x85, - 0x00, 0x63, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0xDE, 0x05, 0x1D, 0x01, 0x18, 0xD4, 0xC0, 0x23, - 0x07, 0x41, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0xC0, 0x05, 0x00, 0x33, 0x37, 0x00, 0x82, 0x88, - 0x1D, 0x01, 0x02, 0xD6, 0x46, 0x23, 0xB8, 0x88, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, - 0xD8, 0x05, 0x00, 0x33, 0x38, 0x00, 0x82, 0x88, 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, - 0x06, 0x41, 0xCB, 0x00, 0x52, 0x00, 0x06, 0x61, 0x00, 0xA2, 0xF2, 0x05, 0xC0, 0x23, 0x07, 0x41, - 0x00, 0x63, 0x80, 0x23, 0x07, 0x41, 0x00, 0x63, 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, - 0x00, 0x63, 0x06, 0xA6, 0x14, 0x06, 0x07, 0xA6, 0x64, 0x06, 0x02, 0xA6, 0xBC, 0x06, 0x00, 0x33, - 0x39, 0x00, 0x82, 0x88, 0x00, 0x00, 0x01, 0xA0, 0xD6, 0x06, 0xA2, 0x95, 0x83, 0x03, 0x80, 0x63, - 0x06, 0xA6, 0x28, 0x06, 0x07, 0xA6, 0x64, 0x06, 0x00, 0x00, 0x00, 0x2B, 0x40, 0x0E, 0x80, 0x63, - 0x01, 0x00, 0x06, 0xA6, 0x40, 0x06, 0x07, 0xA6, 0x64, 0x06, 0x00, 0x33, 0x3A, 0x00, 0x82, 0x88, - 0x40, 0x0E, 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x32, 0x06, 0x06, 0xA6, 0x58, 0x06, 0x07, 0xA6, - 0x64, 0x06, 0x00, 0x33, 0x3B, 0x00, 0x82, 0x88, 0x80, 0x67, 0x40, 0x0E, 0x80, 0x63, 0x07, 0xA6, - 0x64, 0x06, 0x00, 0x63, 0x03, 0x03, 0x80, 0x63, 0x88, 0x00, 0x01, 0xA2, 0x78, 0x06, 0x07, 0xA2, - 0xBC, 0x06, 0x00, 0x33, 0x35, 0x00, 0x82, 0x88, 0x07, 0xA6, 0x82, 0x06, 0x00, 0x33, 0x2A, 0x00, - 0x82, 0x88, 0x03, 0x03, 0x03, 0xA2, 0x8E, 0x06, 0x07, 0x23, 0x80, 0x00, 0xC8, 0x86, 0x80, 0x63, - 0x89, 0x00, 0x0A, 0x2B, 0x07, 0xA6, 0x9E, 0x06, 0x00, 0x33, 0x29, 0x00, 0x82, 0x88, 0x00, 0x43, - 0x00, 0xA2, 0xAA, 0x06, 0xC0, 0x0E, 0x80, 0x63, 0x94, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, + 0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x4E, 0x05, 0x77, 0x04, 0x01, 0x23, 0xEA, 0x00, 0x5D, 0x00, + 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63, 0x07, 0xA4, 0xCC, 0x05, 0x03, 0x03, + 0x02, 0xA0, 0x7C, 0x05, 0xC8, 0x85, 0x00, 0x33, 0x2D, 0x00, 0xC2, 0x88, 0x04, 0xA0, 0xA2, 0x05, + 0x80, 0x63, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x8E, 0x05, 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, + 0x02, 0x41, 0x82, 0x01, 0x50, 0x00, 0x64, 0x97, 0xF0, 0x84, 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, + 0xF0, 0x84, 0x08, 0xA0, 0xA8, 0x05, 0xC8, 0x85, 0x03, 0xA0, 0xAE, 0x05, 0xC8, 0x85, 0x01, 0xA0, + 0xBA, 0x05, 0x88, 0x00, 0x80, 0x63, 0xB8, 0x96, 0x6A, 0x85, 0x07, 0xA0, 0xC6, 0x05, 0x06, 0x23, + 0x6A, 0x98, 0x48, 0x23, 0xF8, 0x88, 0xC8, 0x86, 0x80, 0x63, 0x6A, 0x85, 0x00, 0x63, 0x4A, 0x00, + 0x06, 0x61, 0x00, 0xA2, 0x0A, 0x06, 0x1D, 0x01, 0x18, 0xD4, 0xC0, 0x23, 0x07, 0x41, 0x83, 0x03, + 0x80, 0x63, 0x06, 0xA6, 0xEC, 0x05, 0x00, 0x33, 0x37, 0x00, 0xC2, 0x88, 0x1D, 0x01, 0x02, 0xD6, + 0x46, 0x23, 0xF8, 0x88, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x04, 0x06, 0x00, 0x33, + 0x38, 0x00, 0xC2, 0x88, 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00, + 0x52, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x22, 0x06, 0x1D, 0x01, 0x03, 0xCA, 0xC0, 0x23, 0x07, 0x41, + 0x00, 0x63, 0x1D, 0x01, 0x04, 0xCC, 0x00, 0x33, 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23, + 0x07, 0x41, 0x00, 0x63, 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x06, 0xA6, + 0x50, 0x06, 0x07, 0xA6, 0xA4, 0x06, 0x02, 0xA6, 0xFC, 0x06, 0x00, 0x33, 0x39, 0x00, 0xC2, 0x88, + 0x00, 0x00, 0x01, 0xA0, 0x16, 0x07, 0xCE, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x64, 0x06, + 0x07, 0xA6, 0xA4, 0x06, 0x00, 0x00, 0x01, 0xA0, 0x16, 0x07, 0x00, 0x2B, 0x40, 0x0E, 0x80, 0x63, + 0x01, 0x00, 0x06, 0xA6, 0x80, 0x06, 0x07, 0xA6, 0xA4, 0x06, 0x00, 0x33, 0x3A, 0x00, 0xC2, 0x88, + 0x40, 0x0E, 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x72, 0x06, 0x06, 0xA6, 0x98, 0x06, 0x07, 0xA6, + 0xA4, 0x06, 0x00, 0x33, 0x3B, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x40, 0x0E, 0x80, 0x63, 0x07, 0xA6, + 0xA4, 0x06, 0x00, 0x63, 0x03, 0x03, 0x80, 0x63, 0x88, 0x00, 0x01, 0xA2, 0xB8, 0x06, 0x07, 0xA2, + 0xFC, 0x06, 0x00, 0x33, 0x35, 0x00, 0xC2, 0x88, 0x07, 0xA6, 0xC2, 0x06, 0x00, 0x33, 0x2A, 0x00, + 0xC2, 0x88, 0x03, 0x03, 0x03, 0xA2, 0xCE, 0x06, 0x07, 0x23, 0x80, 0x00, 0x08, 0x87, 0x80, 0x63, + 0x89, 0x00, 0x0A, 0x2B, 0x07, 0xA6, 0xDE, 0x06, 0x00, 0x33, 0x29, 0x00, 0xC2, 0x88, 0x00, 0x43, + 0x00, 0xA2, 0xEA, 0x06, 0xC0, 0x0E, 0x80, 0x63, 0xD4, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20, 0x81, 0x62, 0x04, 0x01, 0x08, 0xDA, 0x80, 0x63, 0x00, 0x63, 0x80, 0x67, 0x00, 0x33, - 0x00, 0x40, 0xC0, 0x20, 0x81, 0x62, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x20, 0x06, - 0x00, 0x33, 0x2C, 0x00, 0x82, 0x88, 0x0C, 0xA2, 0xF0, 0x06, 0xA2, 0x95, 0x83, 0x03, 0x80, 0x63, - 0x06, 0xA6, 0xEE, 0x06, 0x07, 0xA6, 0x64, 0x06, 0x00, 0x33, 0x3D, 0x00, 0x82, 0x88, 0x00, 0x00, - 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x06, 0x07, 0x07, 0xA6, 0x64, 0x06, 0xBF, 0x23, - 0x04, 0x61, 0x84, 0x01, 0xB2, 0x84, 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x00, 0x01, + 0x00, 0x40, 0xC0, 0x20, 0x81, 0x62, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x5C, 0x06, + 0x00, 0x33, 0x2C, 0x00, 0xC2, 0x88, 0x0C, 0xA2, 0x30, 0x07, 0xCE, 0x95, 0x83, 0x03, 0x80, 0x63, + 0x06, 0xA6, 0x2E, 0x07, 0x07, 0xA6, 0xA4, 0x06, 0x00, 0x33, 0x3D, 0x00, 0xC2, 0x88, 0x00, 0x00, + 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x46, 0x07, 0x07, 0xA6, 0xA4, 0x06, 0xBF, 0x23, + 0x04, 0x61, 0x84, 0x01, 0xD2, 0x84, 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x00, 0x01, 0xF2, 0x00, 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04, 0x80, 0x05, 0x81, 0x05, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x70, 0x00, 0x81, 0x01, 0x70, 0x04, 0x71, 0x00, 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04, 0x70, 0x00, 0x80, 0x01, 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01, 0xF1, 0x00, 0x70, 0x00, 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, 0x72, 0x00, 0x81, 0x01, 0x71, 0x04, 0x70, 0x00, 0x81, 0x01, 0x70, 0x04, 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05, 0xA3, 0x01, - 0xA2, 0x01, 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1, 0x86, 0x07, - 0x00, 0x33, 0x07, 0x00, 0x82, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8, 0x48, 0x00, + 0xA2, 0x01, 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1, 0xC6, 0x07, + 0x00, 0x33, 0x07, 0x00, 0xC2, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8, 0x48, 0x00, 0xB0, 0x01, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43, 0x00, 0xA2, - 0xA6, 0x07, 0x00, 0x05, 0x9C, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01, 0x05, 0x05, + 0xE6, 0x07, 0x00, 0x05, 0xDC, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01, 0x05, 0x05, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, - 0x00, 0xA0, 0xD6, 0x07, 0xD8, 0x87, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04, 0x00, 0x63, + 0x00, 0xA0, 0x16, 0x08, 0x18, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43, 0xF4, 0x00, 0xCF, 0x40, 0x00, 0xA2, - 0x06, 0x08, 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1, 0xE6, 0x07, - 0xC6, 0x97, 0xF4, 0x94, 0xE6, 0x87, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04, 0x1C, 0x88, - 0x02, 0x01, 0x04, 0xD8, 0x08, 0x97, 0xC6, 0x97, 0xF4, 0x94, 0x0C, 0x88, 0x75, 0x00, 0x00, 0xA3, - 0x26, 0x08, 0x00, 0x05, 0x10, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, - 0x38, 0x08, 0x00, 0x33, 0x3E, 0x00, 0x82, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, - 0x38, 0x2B, 0x5E, 0x88, 0x38, 0x2B, 0x54, 0x88, 0x32, 0x09, 0x31, 0x05, 0x54, 0x98, 0x05, 0x05, + 0x46, 0x08, 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1, 0x26, 0x08, + 0x06, 0x98, 0x14, 0x95, 0x26, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04, 0x5C, 0x88, + 0x02, 0x01, 0x04, 0xD8, 0x48, 0x97, 0x06, 0x98, 0x14, 0x95, 0x4C, 0x88, 0x75, 0x00, 0x00, 0xA3, + 0x66, 0x08, 0x00, 0x05, 0x50, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, + 0x78, 0x08, 0x00, 0x33, 0x3E, 0x00, 0xC2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, + 0x38, 0x2B, 0x9E, 0x88, 0x38, 0x2B, 0x94, 0x88, 0x32, 0x09, 0x31, 0x05, 0x94, 0x98, 0x05, 0x05, 0xB2, 0x09, 0x00, 0x63, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63, 0x80, 0x32, 0x80, 0x36, 0x80, 0x3A, 0x80, 0x3E, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32, 0x40, 0x36, 0x40, 0x3A, - 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0x74, 0x08, 0x5D, 0x00, 0xFE, 0xC3, + 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0xB4, 0x08, 0x5D, 0x00, 0xFE, 0xC3, 0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73, 0xFF, 0xFD, 0x80, 0x73, - 0x13, 0x23, 0xB8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01, 0xA1, 0x23, 0xA1, 0x01, - 0x81, 0x62, 0xA2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2, 0x80, 0x00, 0x03, 0xC2, - 0xF1, 0xC7, 0x41, 0x23, 0xB8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xB2, 0x84, - + 0x13, 0x23, 0xF8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01, 0xA1, 0x23, 0xA1, 0x01, + 0x81, 0x62, 0xE2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2, 0x80, 0x00, 0x03, 0xC2, + 0xF1, 0xC7, 0x41, 0x23, 0xF8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xD2, 0x84, }; ushort _mcode_size = sizeof (_mcode_buf); -ulong _mcode_chksum = 0x012258FBUL; - -extern uchar _sdtr_period_tbl_[]; +ulong _mcode_chksum = 0x012CD3FFUL; +#define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16 +uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = +{ + SCSICMD_Inquiry, + SCSICMD_RequestSense, + SCSICMD_ReadCapacity, + SCSICMD_ReadTOC, + SCSICMD_ModeSelect6, + SCSICMD_ModeSense6, + SCSICMD_ModeSelect10, + SCSICMD_ModeSense10, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF, + 0xFF +}; int AscExeScsiQueue( - ASC_DVC_VAR asc_ptr_type * asc_dvc, - ASC_SCSI_Q dosfar * scsiq + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_Q dosfar * scsiq ) { PortAddr iop_base; int last_int_level; int sta; + int n_q_required; + int disable_syn_offset_one_fix; + int i; ulong addr; - uchar sg_entry_cnt; + ASC_EXE_CALLBACK asc_exe_callback; + ushort sg_entry_cnt = 0; + ushort sg_entry_cnt_minus_one = 0; uchar target_ix; - int n_q_required; - uchar sg_entry_cnt_minus_one; uchar tid_no; uchar sdtr_data; - ASC_EXE_CALLBACK asc_exe_callback; - -#if CC_DEBUG_SG_LIST - int i; - -#endif + uchar extra_bytes; + uchar scsi_cmd; + uchar disable_cmd; + ASC_SG_HEAD dosfar *sg_head; + ulong data_cnt; #if CC_LINK_BUSY_Q ASC_SCSI_Q dosfar *scsiq_tail; ASC_SCSI_Q dosfar *scsiq_next; ASC_SCSI_Q dosfar *scsiq_prev; - #endif - iop_base = asc_dvc->iop_base; + sg_head = scsiq->sg_head; asc_exe_callback = (ASC_EXE_CALLBACK) asc_dvc->exe_callback; if (asc_dvc->err_code != 0) return (ERR); @@ -6098,20 +6978,17 @@ return (ERR); } scsiq->q1.q_no = 0; + scsiq->q1.extra_bytes = 0; sta = 0; target_ix = scsiq->q2.target_ix; tid_no = ASC_TIX_TO_TID(target_ix); - n_q_required = 1; - if (scsiq->cdbptr[0] == SCSICMD_RequestSense) { - if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) && ((asc_dvc->sdtr_done & scsiq->q1.target_id) != 0)) { - sdtr_data = AscReadLramByte(iop_base, - (ushort) ((ushort) ASCV_SDTR_DATA_BEG + (ushort) tid_no)); - AscMsgOutSDTR(iop_base, - _sdtr_period_tbl_[(sdtr_data >> 4) & (uchar) (ASC_SYN_XFER_NO - 1)], + sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no); + AscMsgOutSDTR(asc_dvc, + asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) & (uchar) (ASC_SYN_XFER_NO - 1)], (uchar) (sdtr_data & (uchar) ASC_SYN_MAX_OFFSET)); scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT); } @@ -6123,33 +7000,30 @@ return (ERR); } asc_dvc->in_critical_cnt++; - if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) { - - if ((sg_entry_cnt = scsiq->sg_head->entry_cnt) == 0) { + if ((sg_entry_cnt = sg_head->entry_cnt) == 0) { asc_dvc->in_critical_cnt--; DvcLeaveCritical(last_int_level); return (ERR); } - if (sg_entry_cnt == 1) { - scsiq->q1.data_addr = scsiq->sg_head->sg_list[0].addr; - scsiq->q1.data_cnt = scsiq->sg_head->sg_list[0].bytes; - scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE); - goto NON_SG_LIST_REQ; - } if (sg_entry_cnt > ASC_MAX_SG_LIST) { - return (ERR); } + if (sg_entry_cnt == 1) { + scsiq->q1.data_addr = sg_head->sg_list[0].addr; + scsiq->q1.data_cnt = sg_head->sg_list[0].bytes; + scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE); + } else { +#if CC_CHK_AND_COALESCE_SG_LIST + AscCoalesceSgList(scsiq); + sg_entry_cnt = sg_head->entry_cnt; +#endif + } sg_entry_cnt_minus_one = sg_entry_cnt - 1; - #if CC_DEBUG_SG_LIST if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) { for (i = 0; i < sg_entry_cnt_minus_one; i++) { - - addr = scsiq->sg_head->sg_list[i].addr + - scsiq->sg_head->sg_list[i].bytes; - + addr = sg_head->sg_list[i].addr + sg_head->sg_list[i].bytes; if (((ushort) addr & 0x0003) != 0) { asc_dvc->in_critical_cnt--; DvcLeaveCritical(last_int_level); @@ -6159,40 +7033,78 @@ } } #endif - + } + scsi_cmd = scsiq->cdbptr[0]; + disable_syn_offset_one_fix = FALSE; + if ( + (asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) + && !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id) + ) { + if (scsiq->q1.cntl & QC_SG_HEAD) { + data_cnt = 0; + for (i = 0; i < sg_entry_cnt; i++) { + data_cnt += sg_head->sg_list[i].bytes; + } + } else { + data_cnt = scsiq->q1.data_cnt; + } + if (data_cnt != 0UL) { + if (data_cnt < 512UL) { + disable_syn_offset_one_fix = TRUE; + } else { + for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST; i++) { + disable_cmd = _syn_offset_one_disable_cmd[i]; + if (disable_cmd == 0xFF) { + break; + } + if (scsi_cmd == disable_cmd) { + disable_syn_offset_one_fix = TRUE; + break; + } + } + } + } + } + if (disable_syn_offset_one_fix) { + scsiq->q2.tag_code &= ~M2_QTAG_MSG_SIMPLE; + scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX | + ASC_TAG_FLAG_DISABLE_DISCONNECT); + } else { + scsiq->q2.tag_code &= 0x23; + } + if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) { if (asc_dvc->bug_fix_cntl) { - if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ADD_ONE_BYTE) { - - addr = scsiq->sg_head->sg_list[sg_entry_cnt_minus_one].addr + - scsiq->sg_head->sg_list[sg_entry_cnt_minus_one].bytes; - if (((ushort) addr & 0x0003) != 0) { - if ((scsiq->cdbptr[0] == SCSICMD_Read6) || - (scsiq->cdbptr[0] == SCSICMD_Read10)) { - if ((scsiq->q2.tag_code & ASC_TAG_FLAG_ADD_ONE_BYTE) == 0) { - - scsiq->sg_head->sg_list[sg_entry_cnt_minus_one].bytes++; - scsiq->q2.tag_code |= ASC_TAG_FLAG_ADD_ONE_BYTE; - } + if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) { + if ( + (scsi_cmd == SCSICMD_Read6) + || (scsi_cmd == SCSICMD_Read10) + ) { + addr = sg_head->sg_list[sg_entry_cnt_minus_one].addr + + sg_head->sg_list[sg_entry_cnt_minus_one].bytes; + extra_bytes = (uchar) ((ushort) addr & 0x0003); + if (extra_bytes != 0) { + scsiq->q2.tag_code |= ASC_TAG_FLAG_EXTRA_BYTES; + scsiq->q1.extra_bytes = extra_bytes; + sg_head->sg_list[sg_entry_cnt_minus_one].bytes -= (ulong) extra_bytes; } } } } - scsiq->sg_head->entry_to_copy = scsiq->sg_head->entry_cnt; + sg_head->entry_to_copy = sg_head->entry_cnt; n_q_required = AscSgListToQueue(sg_entry_cnt); - #if CC_LINK_BUSY_Q scsiq_next = (ASC_SCSI_Q dosfar *) asc_dvc->scsiq_busy_head[tid_no]; if (scsiq_next != (ASC_SCSI_Q dosfar *) 0L) { goto link_scisq_to_busy_list; } #endif - - if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) - >= (uint) n_q_required) || - ((scsiq->q1.cntl & QC_URGENT) != 0)) { + if ( + (AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) + >= (uint) n_q_required) || + ((scsiq->q1.cntl & QC_URGENT) != 0) + ) { if ((sta = AscSendScsiQueue(asc_dvc, scsiq, n_q_required)) == 1) { - asc_dvc->in_critical_cnt--; if (asc_exe_callback != 0) { (*asc_exe_callback) (asc_dvc, scsiq); @@ -6202,30 +7114,25 @@ } } } else { - - NON_SG_LIST_REQ: - if (asc_dvc->bug_fix_cntl) { - if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ADD_ONE_BYTE) { - - addr = scsiq->q1.data_addr + scsiq->q1.data_cnt; - if ((scsiq->cdbptr[0] == SCSICMD_Read6) || - (scsiq->cdbptr[0] == SCSICMD_Read10)) { - if (((ushort) addr & 0x0003) != 0) { + if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) { + if ( + (scsi_cmd == SCSICMD_Read6) + || (scsi_cmd == SCSICMD_Read10) + ) { + addr = scsiq->q1.data_addr + scsiq->q1.data_cnt; + extra_bytes = (uchar) ((ushort) addr & 0x0003); + if (extra_bytes != 0) { if (((ushort) scsiq->q1.data_cnt & 0x01FF) == 0) { - - if ((scsiq->q2.tag_code & ASC_TAG_FLAG_ADD_ONE_BYTE) == 0) { - - scsiq->q2.tag_code |= ASC_TAG_FLAG_ADD_ONE_BYTE; - scsiq->q1.data_cnt++; - } + scsiq->q2.tag_code |= ASC_TAG_FLAG_EXTRA_BYTES; + scsiq->q1.data_cnt -= (ulong) extra_bytes; + scsiq->q1.extra_bytes = extra_bytes; } } } } } n_q_required = 1; - #if CC_LINK_BUSY_Q scsiq_next = (ASC_SCSI_Q dosfar *) asc_dvc->scsiq_busy_head[tid_no]; if (scsiq_next != (ASC_SCSI_Q dosfar *) 0L) { @@ -6236,7 +7143,6 @@ ((scsiq->q1.cntl & QC_URGENT) != 0)) { if ((sta = AscSendScsiQueue(asc_dvc, scsiq, n_q_required)) == 1) { - asc_dvc->in_critical_cnt--; if (asc_exe_callback != 0) { (*asc_exe_callback) (asc_dvc, scsiq); @@ -6246,10 +7152,8 @@ } } } - #if CC_LINK_BUSY_Q if (sta == 0) { - link_scisq_to_busy_list: scsiq->ext.q_required = n_q_required; if (scsiq_next == (ASC_SCSI_Q dosfar *) 0L) { @@ -6263,7 +7167,6 @@ scsiq_tail = (ASC_SCSI_Q dosfar *) asc_dvc->scsiq_busy_tail[tid_no]; if (scsiq_tail->ext.next == (ASC_SCSI_Q dosfar *) 0L) { if ((scsiq->q1.cntl & QC_URGENT) != 0) { - asc_dvc->scsiq_busy_head[tid_no] = (ASC_SCSI_Q dosfar *) scsiq; scsiq->ext.next = scsiq_next; scsiq->ext.join = (ASC_SCSI_Q dosfar *) 0L; @@ -6275,7 +7178,6 @@ if (scsiq->ext.lba < scsiq_prev->ext.lba) break; } while (scsiq_next != (ASC_SCSI_Q dosfar *) 0L); - scsiq_prev->ext.next = scsiq; scsiq->ext.next = scsiq_next; if (scsiq_next == (ASC_SCSI_Q dosfar *) 0L) { @@ -6283,7 +7185,6 @@ } scsiq->ext.join = (ASC_SCSI_Q dosfar *) 0L; } else { - scsiq_tail->ext.next = (ASC_SCSI_Q dosfar *) scsiq; asc_dvc->scsiq_busy_tail[tid_no] = (ASC_SCSI_Q dosfar *) scsiq; scsiq->ext.next = (ASC_SCSI_Q dosfar *) 0L; @@ -6293,7 +7194,6 @@ scsiq->q1.status = QS_BUSY; sta = 1; } else { - AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_BAD_NEXT_PTR); sta = ERR; } @@ -6307,8 +7207,8 @@ int AscSendScsiQueue( - ASC_DVC_VAR asc_ptr_type * asc_dvc, - ASC_SCSI_Q dosfar * scsiq, + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_Q dosfar * scsiq, uchar n_q_required ) { @@ -6318,7 +7218,6 @@ uchar tid_no; uchar target_ix; int sta; - iop_base = asc_dvc->iop_base; target_ix = scsiq->q2.target_ix; tid_no = ASC_TIX_TO_TID(target_ix); @@ -6331,14 +7230,11 @@ asc_dvc->last_q_shortage = 0; scsiq->sg_head->queue_cnt = n_q_required - 1; scsiq->q1.q_no = free_q_head; - if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq, free_q_head)) == 1) { - #if CC_WRITE_IO_COUNT asc_dvc->req_count++; #endif - AscPutVarFreeQHead(iop_base, next_qp); asc_dvc->cur_total_qng += (uchar) (n_q_required); asc_dvc->cur_dvc_qng[tid_no]++; @@ -6346,18 +7242,14 @@ return (sta); } } else if (n_q_required == 1) { - if ((next_qp = AscAllocFreeQueue(iop_base, free_q_head)) != ASC_QLINK_END) { - scsiq->q1.q_no = free_q_head; if ((sta = AscPutReadyQueue(asc_dvc, scsiq, free_q_head)) == 1) { - #if CC_WRITE_IO_COUNT asc_dvc->req_count++; #endif - AscPutVarFreeQHead(iop_base, next_qp); asc_dvc->cur_total_qng++; asc_dvc->cur_dvc_qng[tid_no]++; @@ -6374,24 +7266,24 @@ ) { int n_sg_list_qs; - n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q); if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0) n_sg_list_qs++; return (n_sg_list_qs + 1); } + uint AscGetNumOfFreeQueue( - ASC_DVC_VAR asc_ptr_type * asc_dvc, - uchar target_ix, uchar n_qs + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + uchar target_ix, + uchar n_qs ) { uint cur_used_qs; uint cur_free_qs; ASC_SCSI_BIT_ID_TYPE target_id; uchar tid_no; - target_id = ASC_TIX_TO_TARGET_ID(target_ix); tid_no = ASC_TIX_TO_TID(target_ix); if ((asc_dvc->unit_not_ready & target_id) || @@ -6406,7 +7298,6 @@ cur_used_qs = (uint) asc_dvc->cur_total_qng + (uint) ASC_MIN_FREE_Q; } - if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) { cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs; if (asc_dvc->cur_dvc_qng[tid_no] >= @@ -6425,8 +7316,8 @@ int AscPutReadyQueue( - ASC_DVC_VAR asc_ptr_type * asc_dvc, - ASC_SCSI_Q dosfar * scsiq, + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_Q dosfar * scsiq, uchar q_no ) { @@ -6436,55 +7327,41 @@ uchar syn_period_ix; uchar syn_offset; PortAddr iop_base; - iop_base = asc_dvc->iop_base; - if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) && ((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) { - tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix); - - sdtr_data = AscReadLramByte(iop_base, - (ushort) ((ushort) ASCV_SDTR_DATA_BEG + (ushort) tid_no)); + sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no); syn_period_ix = (sdtr_data >> 4) & (ASC_SYN_XFER_NO - 1); syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET; - AscMsgOutSDTR(iop_base, - _sdtr_period_tbl_[syn_period_ix], + AscMsgOutSDTR(asc_dvc, + asc_dvc->sdtr_period_tbl[syn_period_ix], syn_offset); - scsiq->q1.cntl |= QC_MSG_OUT; } q_addr = ASC_QNO_TO_QADDR(q_no); - if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) { scsiq->q2.tag_code &= ~M2_QTAG_MSG_SIMPLE; } scsiq->q1.status = QS_FREE; - AscMemWordCopyToLram(iop_base, (ushort) (q_addr + (ushort) ASC_SCSIQ_CDB_BEG), (ushort dosfar *) scsiq->cdbptr, (ushort) ((ushort) scsiq->q2.cdb_len >> 1)); - #if !CC_LITTLE_ENDIAN_HOST AscAdjEndianScsiQ(scsiq); #endif - DvcPutScsiQ(iop_base, (ushort) (q_addr + (ushort) ASC_SCSIQ_CPY_BEG), (ushort dosfar *) & scsiq->q1.cntl, (ushort) ((((sizeof (ASC_SCSIQ_1) + sizeof (ASC_SCSIQ_2)) / 2) - 1))); - #if CC_WRITE_IO_COUNT AscWriteLramWord(iop_base, (ushort) (q_addr + (ushort) ASC_SCSIQ_W_REQ_COUNT), (ushort) asc_dvc->req_count); - #endif - #if CC_VERIFY_LRAM_COPY if ((asc_dvc->dvc_cntl & ASC_CNTL_NO_VERIFY_COPY) == 0) { - if (AscMemWordCmpToLram(iop_base, (ushort) (q_addr + (ushort) ASC_SCSIQ_CDB_BEG), (ushort dosfar *) scsiq->cdbptr, @@ -6502,16 +7379,12 @@ } } #endif - #if CC_CLEAR_DMA_REMAIN - AscWriteLramDWord(iop_base, (ushort) (q_addr + (ushort) ASC_SCSIQ_DW_REMAIN_XFER_ADDR), 0UL); AscWriteLramDWord(iop_base, (ushort) (q_addr + (ushort) ASC_SCSIQ_DW_REMAIN_XFER_CNT), 0UL); - #endif - AscWriteLramWord(iop_base, (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS), (ushort) (((ushort) scsiq->q1.q_no << 8) | (ushort) QS_READY)); @@ -6520,27 +7393,25 @@ int AscPutReadySgListQueue( - ASC_DVC_VAR asc_ptr_type * asc_dvc, - ASC_SCSI_Q dosfar * scsiq, + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_Q dosfar * scsiq, uchar q_no ) { - uchar sg_list_dwords; - uchar sg_index, i; - uchar sg_entry_cnt; - uchar next_qp; - ushort q_addr; int sta; + int i; ASC_SG_HEAD dosfar *sg_head; ASC_SG_LIST_Q scsi_sg_q; ulong saved_data_addr; ulong saved_data_cnt; PortAddr iop_base; - + ushort sg_list_dwords; + ushort sg_index; + ushort sg_entry_cnt; + ushort q_addr; + uchar next_qp; iop_base = asc_dvc->iop_base; - sg_head = scsiq->sg_head; - saved_data_addr = scsiq->q1.data_addr; saved_data_cnt = scsiq->q1.data_cnt; scsiq->q1.data_addr = sg_head->sg_list[0].addr; @@ -6566,7 +7437,6 @@ scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q - 1; } } else { - scsi_sg_q.cntl |= QCSG_SG_XFER_END; sg_list_dwords = sg_entry_cnt << 1; if (i == 0) { @@ -6582,25 +7452,20 @@ (ushort) (q_addr + ASC_SCSIQ_B_FWD)); scsi_sg_q.q_no = next_qp; q_addr = ASC_QNO_TO_QADDR(next_qp); - AscMemWordCopyToLram(iop_base, (ushort) (q_addr + ASC_SCSIQ_SGHD_CPY_BEG), (ushort dosfar *) & scsi_sg_q, (ushort) (sizeof (ASC_SG_LIST_Q) >> 1)); - AscMemDWordCopyToLram(iop_base, (ushort) (q_addr + ASC_SGQ_LIST_BEG), (ulong dosfar *) & sg_head->sg_list[sg_index], (ushort) sg_list_dwords); - sg_index += ASC_SG_LIST_PER_Q; } } else { - scsiq->q1.cntl &= ~QC_SG_HEAD; } sta = AscPutReadyQueue(asc_dvc, scsiq, q_no); - scsiq->q1.data_addr = saved_data_addr; scsiq->q1.data_cnt = saved_data_cnt; return (sta); @@ -6608,14 +7473,13 @@ int AscAbortSRB( - ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, ulong srb_ptr ) { int sta; ASC_SCSI_BIT_ID_TYPE saved_unit_not_ready; PortAddr iop_base; - iop_base = asc_dvc->iop_base; sta = ERR; saved_unit_not_ready = asc_dvc->unit_not_ready; @@ -6626,7 +7490,6 @@ sta = 1; AscCleanUpBusyQueue(iop_base); AscStartQueueExe(iop_base); - } else { sta = 0; AscStartQueueExe(iop_base); @@ -6638,7 +7501,7 @@ int AscResetDevice( - ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, uchar target_ix ) { @@ -6651,7 +7514,6 @@ ASC_SCSI_REQ_Q dosfar *scsiq; uchar dosfar *buf; ASC_SCSI_BIT_ID_TYPE saved_unit_not_ready; - iop_base = asc_dvc->iop_base; tid_no = ASC_TIX_TO_TID(target_ix); target_id = ASC_TID_TO_TARGET_ID(tid_no); @@ -6661,56 +7523,43 @@ AscWaitTixISRDone(asc_dvc, target_ix); if (AscStopQueueExe(iop_base) == 1) { if (AscRiscHaltedAbortTIX(asc_dvc, target_ix) == 1) { - AscCleanUpBusyQueue(iop_base); AscStartQueueExe(iop_base); - AscWaitTixISRDone(asc_dvc, target_ix); - sta = TRUE; scsiq = (ASC_SCSI_REQ_Q dosfar *) & scsiq_buf; buf = (uchar dosfar *) & scsiq_buf; for (i = 0; i < sizeof (ASC_SCSI_REQ_Q); i++) { *buf++ = 0x00; } - scsiq->r1.status = (uchar) QS_READY; scsiq->r2.cdb_len = 6; scsiq->r2.tag_code = M2_QTAG_MSG_SIMPLE; scsiq->r1.target_id = target_id; - scsiq->r2.target_ix = ASC_TIDLUN_TO_IX(tid_no, 0); scsiq->cdbptr = (uchar dosfar *) scsiq->cdb; - scsiq->r1.cntl = QC_NO_CALLBACK | QC_MSG_OUT | QC_URGENT; AscWriteLramByte(asc_dvc->iop_base, ASCV_MSGOUT_BEG, M1_BUS_DVC_RESET); - asc_dvc->unit_not_ready &= ~target_id; - asc_dvc->sdtr_done |= target_id; - if (AscExeScsiQueue(asc_dvc, (ASC_SCSI_Q dosfar *) scsiq) == 1) { asc_dvc->unit_not_ready = target_id; DvcSleepMilliSecond(1000); _AscWaitQDone(iop_base, (ASC_SCSI_Q dosfar *) scsiq); if (AscStopQueueExe(iop_base) == 1) { - AscCleanUpDiscQueue(iop_base); AscStartQueueExe(iop_base); if (asc_dvc->pci_fix_asyn_xfer & target_id) { - AscSetRunChipSynRegAtID(iop_base, tid_no, ASYN_SDTR_DATA_FIX_PCI_REV_AB); } AscWaitTixISRDone(asc_dvc, target_ix); } } else { - sta = 0; } - asc_dvc->sdtr_done &= ~target_id; } else { sta = ERR; @@ -6723,41 +7572,28 @@ int AscResetSB( - ASC_DVC_VAR asc_ptr_type * asc_dvc + REG ASC_DVC_VAR asc_ptr_type * asc_dvc ) { int sta; int i; PortAddr iop_base; - iop_base = asc_dvc->iop_base; asc_dvc->unit_not_ready = 0xFF; sta = TRUE; AscWaitISRDone(asc_dvc); AscStopQueueExe(iop_base); - asc_dvc->sdtr_done = 0; AscResetChipAndScsiBus(iop_base); - DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000)); - -#if CC_SCAM - if (!(asc_dvc->dvc_cntl & ASC_CNTL_NO_SCAM)) { - AscSCAM(asc_dvc); - } -#endif AscReInitLram(asc_dvc); - for (i = 0; i <= ASC_MAX_TID; i++) { asc_dvc->cur_dvc_qng[i] = 0; - if (asc_dvc->pci_fix_asyn_xfer & (0x01 << i)) { - + if (asc_dvc->pci_fix_asyn_xfer & (ASC_SCSI_BIT_ID_TYPE) (0x01 << i)) { AscSetChipSynRegAtID(iop_base, i, ASYN_SDTR_DATA_FIX_PCI_REV_AB); } } - asc_dvc->err_code = 0; - AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR); if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) { sta = ERR; @@ -6779,10 +7615,8 @@ ) { int sta = FALSE; - if (AscHostReqRiscHalt(iop_base)) { sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data); - AscStartChip(iop_base); return (sta); } @@ -6796,22 +7630,36 @@ uchar sdtr_data ) { + ASC_SCSI_BIT_ID_TYPE org_id; + int i; + int sta; + sta = TRUE; AscSetBank(iop_base, 1); - AscWriteChipScsiID(iop_base, id); - if (AscReadChipScsiID(iop_base) != (0x01 << id)) { - return (FALSE); + org_id = AscReadChipDvcID(iop_base); + for (i = 0; i <= ASC_MAX_TID; i++) { + if (org_id == (0x01 << i)) + break; } - AscSetBank(iop_base, 0); - AscWriteChipSyn(iop_base, sdtr_data); - if (AscReadChipSyn(iop_base) != sdtr_data) { - return (FALSE); + org_id = i; + AscWriteChipDvcID(iop_base, id); + if (AscReadChipDvcID(iop_base) == (0x01 << id)) { + AscSetBank(iop_base, 0); + AscSetChipSyn(iop_base, sdtr_data); + if (AscGetChipSyn(iop_base) != sdtr_data) { + sta = FALSE; + } + } else { + sta = FALSE; } - return (TRUE); + AscSetBank(iop_base, 1); + AscWriteChipDvcID(iop_base, org_id); + AscSetBank(iop_base, 0); + return (sta); } int AscReInitLram( - ASC_DVC_VAR asc_ptr_type * asc_dvc + REG ASC_DVC_VAR asc_ptr_type * asc_dvc ) { AscInitLram(asc_dvc); @@ -6821,23 +7669,20 @@ ushort AscInitLram( - ASC_DVC_VAR asc_ptr_type * asc_dvc) + REG ASC_DVC_VAR asc_ptr_type * asc_dvc +) { uchar i; ushort s_addr; PortAddr iop_base; ushort warn_code; - iop_base = asc_dvc->iop_base; warn_code = 0; - AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0, (ushort) (((int) (asc_dvc->max_total_qng + 2 + 1) * 64) >> 1) ); - i = ASC_MIN_ACTIVE_QNO; s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE; - AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_FWD), (uchar) (i + 1)); AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_BWD), @@ -6854,7 +7699,6 @@ AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_QNO), (uchar) i); } - AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_FWD), (uchar) ASC_QLINK_END); AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_BWD), @@ -6863,10 +7707,8 @@ (uchar) asc_dvc->max_total_qng); i++; s_addr += ASC_QBLK_SIZE; - for (; i <= (uchar) (asc_dvc->max_total_qng + 3); i++, s_addr += ASC_QBLK_SIZE) { - AscWriteLramByte(iop_base, (ushort) (s_addr + (ushort) ASC_SCSIQ_B_FWD), i); AscWriteLramByte(iop_base, @@ -6874,58 +7716,48 @@ AscWriteLramByte(iop_base, (ushort) (s_addr + (ushort) ASC_SCSIQ_B_QNO), i); } - return (warn_code); } ushort AscInitQLinkVar( - ASC_DVC_VAR asc_ptr_type * asc_dvc + REG ASC_DVC_VAR asc_ptr_type * asc_dvc ) { PortAddr iop_base; int i; ushort lram_addr; - iop_base = asc_dvc->iop_base; AscPutRiscVarFreeQHead(iop_base, 1); AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng); - AscPutVarFreeQHead(iop_base, 1); AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng); - AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B, (uchar) ((int) asc_dvc->max_total_qng + 1)); AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B, (uchar) ((int) asc_dvc->max_total_qng + 2)); - AscWriteLramByte(iop_base, (ushort) ASCV_TOTAL_READY_Q_B, asc_dvc->max_total_qng); - AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0); AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0); AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0); AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0); - - AscWriteLramByte(iop_base, (ushort) ASCV_CDBCNT_B, 0); - + AscPutQDoneInProgress(iop_base, 0); lram_addr = ASC_QADR_BEG; for (i = 0; i < 32; i++, lram_addr += 2) { AscWriteLramWord(iop_base, lram_addr, 0); } - return (0); } int AscSetLibErrorCode( - ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, ushort err_code ) { if (asc_dvc->err_code == 0) { - asc_dvc->err_code = err_code; AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W, err_code); @@ -6933,19 +7765,18 @@ return (err_code); } + int _AscWaitQDone( PortAddr iop_base, - ASC_SCSI_Q dosfar * scsiq + REG ASC_SCSI_Q dosfar * scsiq ) { ushort q_addr; uchar q_status; int count = 0; - while (scsiq->q1.q_no == 0) ; q_addr = ASC_QNO_TO_QADDR(scsiq->q1.q_no); - do { q_status = AscReadLramByte(iop_base, q_addr + ASC_SCSIQ_B_STATUS); DvcSleepMilliSecond(100L); @@ -6956,56 +7787,52 @@ return (1); } -uchar _sdtr_period_tbl_[ASC_SYN_XFER_NO] = -{ - SYN_XFER_NS_0, - SYN_XFER_NS_1, - SYN_XFER_NS_2, - SYN_XFER_NS_3, - SYN_XFER_NS_4, - SYN_XFER_NS_5, - SYN_XFER_NS_6, - SYN_XFER_NS_7}; - uchar AscMsgOutSDTR( - PortAddr iop_base, + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, uchar sdtr_period, uchar sdtr_offset ) { SDTR_XMSG sdtr_buf; uchar sdtr_period_index; - + PortAddr iop_base; + iop_base = asc_dvc->iop_base; sdtr_buf.msg_type = MS_EXTEND; sdtr_buf.msg_len = MS_SDTR_LEN; sdtr_buf.msg_req = MS_SDTR_CODE; sdtr_buf.xfer_period = sdtr_period; sdtr_offset &= ASC_SYN_MAX_OFFSET; sdtr_buf.req_ack_offset = sdtr_offset; - AscMemWordCopyToLram(iop_base, ASCV_MSGOUT_BEG, - (ushort dosfar *) & sdtr_buf, SYN_XMSG_WLEN); - if ((sdtr_period_index = AscGetSynPeriodIndex(sdtr_period)) <= - ASC_MAX_SDTR_PERIOD_INDEX) { + if ((sdtr_period_index = + AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <= + asc_dvc->max_sdtr_index) { + AscMemWordCopyToLram(iop_base, + ASCV_MSGOUT_BEG, + (ushort dosfar *) & sdtr_buf, SYN_XMSG_WLEN); return ((sdtr_period_index << 4) | sdtr_offset); } else { - + sdtr_buf.req_ack_offset = 0; + AscMemWordCopyToLram(iop_base, + ASCV_MSGOUT_BEG, + (ushort dosfar *) & sdtr_buf, SYN_XMSG_WLEN); return (0); } } uchar AscCalSDTRData( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, uchar sdtr_period, uchar syn_offset ) { uchar byte; uchar sdtr_period_ix; - - sdtr_period_ix = AscGetSynPeriodIndex(sdtr_period); - if ((sdtr_period_ix > ASC_MAX_SDTR_PERIOD_INDEX) || - (sdtr_period_ix > ASC_SDTR_PERIOD_IX_MIN)) { + sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period); + if ( + (sdtr_period_ix > asc_dvc->max_sdtr_index) + ) { return (0xFF); } byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET); @@ -7019,51 +7846,34 @@ uchar tid_no ) { - - AscWriteChipSyn(iop_base, sdtr_data); - AscWriteLramByte(iop_base, - (ushort) ((ushort) ASCV_SDTR_DONE_BEG + (ushort) tid_no), - sdtr_data); + AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data); + AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data); return; } uchar AscGetSynPeriodIndex( - uchar syn_time + ASC_DVC_VAR asc_ptr_type * asc_dvc, + ruchar syn_time ) { - if ((syn_time >= SYN_XFER_NS_0) && (syn_time <= SYN_XFER_NS_7)) { - if (syn_time <= SYN_XFER_NS_6) { - if (syn_time <= SYN_XFER_NS_5) { - if (syn_time <= SYN_XFER_NS_4) { - if (syn_time <= SYN_XFER_NS_3) { - if (syn_time <= SYN_XFER_NS_2) { - if (syn_time <= SYN_XFER_NS_1) { - if (syn_time <= SYN_XFER_NS_0) { - return (0); - } else - return (1); - } else { - return (2); - } - } else { - return (3); - } - } else { - return (4); - } - } else { - return (5); - } - } else { - return (6); + ruchar *period_table; + int max_index; + int i; + period_table = asc_dvc->sdtr_period_tbl; + max_index = (int) asc_dvc->max_sdtr_index; + if ( + (syn_time >= period_table[0]) + && (syn_time <= period_table[max_index]) + ) { + for (i = 0; i < (max_index - 1); i++) { + if (syn_time <= period_table[i]) { + return (i); } - } else { - return (7); } + return (max_index); } else { - - return (8); + return (max_index + 1); } } @@ -7076,14 +7886,15 @@ ushort q_addr; uchar next_qp; uchar q_status; - q_addr = ASC_QNO_TO_QADDR(free_q_head); q_status = (uchar) AscReadLramByte(iop_base, (ushort) (q_addr + ASC_SCSIQ_B_STATUS)); next_qp = AscReadLramByte(iop_base, (ushort) (q_addr + ASC_SCSIQ_B_FWD)); - if (((q_status & QS_READY) == 0) && - (next_qp != ASC_QLINK_END)) { + if ( + ((q_status & QS_READY) == 0) + && (next_qp != ASC_QLINK_END) + ) { return (next_qp); } return (ASC_QLINK_END); @@ -7097,7 +7908,6 @@ ) { uchar i; - for (i = 0; i < n_free_q; i++) { if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head)) == ASC_QLINK_END) { @@ -7109,7 +7919,7 @@ int AscRiscHaltedAbortSRB( - ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, ulong srb_ptr ) { @@ -7120,16 +7930,13 @@ ASC_QDONE_INFO dosfar *scsiq; ASC_ISR_CALLBACK asc_isr_callback; int last_int_level; - iop_base = asc_dvc->iop_base; asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback; last_int_level = DvcEnterCritical(); scsiq = (ASC_QDONE_INFO dosfar *) & scsiq_buf; - #if CC_LINK_BUSY_Q _AscAbortSrbBusyQueue(asc_dvc, scsiq, srb_ptr); #endif - for (q_no = ASC_MIN_ACTIVE_QNO; q_no <= asc_dvc->max_total_qng; q_no++) { q_addr = ASC_QNO_TO_QADDR(q_no); @@ -7137,10 +7944,11 @@ (ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR)); if (scsiq->d2.srb_ptr == srb_ptr) { _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq, asc_dvc->max_dma_count); - if (((scsiq->q_status & QS_READY) != 0) && - ((scsiq->q_status & QS_ABORTED) == 0) && - ((scsiq->cntl & QCSG_SG_XFER_LIST) == 0)) { - + if ( + ((scsiq->q_status & QS_READY) != 0) + && ((scsiq->q_status & QS_ABORTED) == 0) + && ((scsiq->cntl & QCSG_SG_XFER_LIST) == 0) + ) { scsiq->q_status |= QS_ABORTED; scsiq->d3.done_stat = QD_ABORTED_BY_HOST; AscWriteLramDWord(iop_base, @@ -7160,7 +7968,7 @@ int AscRiscHaltedAbortTIX( - ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, uchar target_ix ) { @@ -7171,39 +7979,32 @@ ASC_QDONE_INFO dosfar *scsiq; ASC_ISR_CALLBACK asc_isr_callback; int last_int_level; - #if CC_LINK_BUSY_Q uchar tid_no; - #endif - iop_base = asc_dvc->iop_base; asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback; last_int_level = DvcEnterCritical(); scsiq = (ASC_QDONE_INFO dosfar *) & scsiq_buf; - #if CC_LINK_BUSY_Q - tid_no = ASC_TIX_TO_TID(target_ix); _AscAbortTidBusyQueue(asc_dvc, scsiq, tid_no); - #endif - for (q_no = ASC_MIN_ACTIVE_QNO; q_no <= asc_dvc->max_total_qng; q_no++) { q_addr = ASC_QNO_TO_QADDR(q_no); _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq, asc_dvc->max_dma_count); - if (((scsiq->q_status & QS_READY) != 0) && - ((scsiq->q_status & QS_ABORTED) == 0) && - ((scsiq->cntl & QCSG_SG_XFER_LIST) == 0)) { + if ( + ((scsiq->q_status & QS_READY) != 0) + && ((scsiq->q_status & QS_ABORTED) == 0) + && ((scsiq->cntl & QCSG_SG_XFER_LIST) == 0) + ) { if (scsiq->d2.target_ix == target_ix) { scsiq->q_status |= QS_ABORTED; scsiq->d3.done_stat = QD_ABORTED_BY_HOST; - AscWriteLramDWord(iop_base, (ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR), 0L); - AscWriteLramByte(iop_base, (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS), scsiq->q_status); @@ -7227,11 +8028,9 @@ int count = 0; int sta = 0; uchar saved_stop_code; - if (AscIsChipHalted(iop_base)) return (1); saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B); - AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP ); @@ -7242,7 +8041,6 @@ } DvcSleepMilliSecond(100); } while (count++ < 20); - AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code); return (sta); } @@ -7253,14 +8051,14 @@ ) { int count; - count = 0; if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) { AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, ASC_STOP_REQ_RISC_STOP); do { - if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) & - ASC_STOP_ACK_RISC_STOP) { + if ( + AscReadLramByte(iop_base, ASCV_STOP_CODE_B) & + ASC_STOP_ACK_RISC_STOP) { return (1); } DvcSleepMilliSecond(100); @@ -7287,7 +8085,6 @@ { int count; uchar stop_code; - count = 0; if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) { AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, @@ -7309,7 +8106,6 @@ { int count; uchar stop_code; - count = 0; if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) { AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, @@ -7332,7 +8128,6 @@ { uchar cur_req; uchar tid_no; - tid_no = ASC_TIX_TO_TID(target_ix); while (TRUE) { if ((cur_req = asc_dvc->cur_dvc_qng[tid_no]) == 0) { @@ -7348,11 +8143,10 @@ int AscWaitISRDone( - ASC_DVC_VAR asc_ptr_type * asc_dvc + REG ASC_DVC_VAR asc_ptr_type * asc_dvc ) { int tid; - for (tid = 0; tid <= ASC_MAX_TID; tid++) { AscWaitTixISRDone(asc_dvc, ASC_TID_TO_TIX(tid)); } @@ -7361,13 +8155,12 @@ ulong AscGetOnePhyAddr( - ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, uchar dosfar * buf_addr, ulong buf_size ) { ASC_MIN_SG_HEAD sg_head; - sg_head.entry_cnt = ASC_MIN_SG_LIST; if (DvcGetSGList(asc_dvc, (uchar dosfar *) buf_addr, buf_size, (ASC_SG_HEAD dosfar *) & sg_head) != buf_size) { @@ -7379,6 +8172,23 @@ return (sg_head.sg_list[0].addr); } +void +DvcDelayNanoSecond( + ASC_DVC_VAR asc_ptr_type * asc_dvc, + ulong nano_sec +) +{ + ulong loop; + PortAddr iop_base; + iop_base = asc_dvc->iop_base; + loop = nano_sec / 90; + loop++; + while (loop-- != 0) { + inp(iop_base); + } + return; +} + ulong AscGetEisaProductID( PortAddr iop_base @@ -7387,7 +8197,6 @@ PortAddr eisa_iop; ushort product_id_high, product_id_low; ulong product_id; - eisa_iop = ASC_GET_EISA_SLOT(iop_base) | ASC_EISA_PID_IOP_MASK; product_id_low = inpw(eisa_iop); product_id_high = inpw(eisa_iop + 2); @@ -7401,7 +8210,6 @@ ) { ulong eisa_product_id; - if (iop_base == 0) { iop_base = ASC_EISA_MIN_IOP_ADDR; } else { @@ -7414,12 +8222,12 @@ } } while (iop_base <= ASC_EISA_MAX_IOP_ADDR) { - eisa_product_id = AscGetEisaProductID(iop_base); - if ((eisa_product_id == ASC_EISA_ID_740) || - (eisa_product_id == ASC_EISA_ID_750)) { + if ( + (eisa_product_id == ASC_EISA_ID_740) + || (eisa_product_id == ASC_EISA_ID_750) + ) { if (AscFindSignature(iop_base)) { - inpw(iop_base + 4); return (iop_base); } @@ -7453,7 +8261,6 @@ ) { uchar cc_val; - cc_val = AscGetChipControl(iop_base) & (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG)); AscSetChipControl(iop_base, (uchar) (cc_val | CC_HALT)); AscSetChipIH(iop_base, INS_HALT); @@ -7469,7 +8276,6 @@ PortAddr iop_base ) { - if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) { if ((AscGetChipControl(iop_base) & CC_HALT) != 0) { return (1); @@ -7495,11 +8301,9 @@ PortAddr iop_base ) { - uchar host_flag; uchar risc_flag; ushort loop; - loop = 0; do { risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B); @@ -7507,21 +8311,17 @@ break; } } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0); - - host_flag = AscReadLramByte(iop_base, ASCV_HOST_FLAG_B); + host_flag = AscReadLramByte(iop_base, ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT); AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, (uchar) (host_flag | ASC_HOST_FLAG_ACK_INT)); - AscSetChipStatus(iop_base, CIW_INT_ACK); loop = 0; while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) { - AscSetChipStatus(iop_base, CIW_INT_ACK); if (loop++ > 3) { break; } } - AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag); return; } @@ -7532,7 +8332,6 @@ ) { ushort cfg; - cfg = AscGetChipCfgLsw(iop_base); AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON)); return; @@ -7544,12 +8343,13 @@ ) { ushort cfg; - cfg = AscGetChipCfgLsw(iop_base); AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON); return; } + + void AscSetBank( PortAddr iop_base, @@ -7557,7 +8357,6 @@ ) { uchar val; - val = AscGetChipControl(iop_base) & (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET | CC_CHIP_RESET)); if (bank == 1) { @@ -7571,31 +8370,47 @@ return; } + + int AscResetChipAndScsiBus( PortAddr iop_base ) { + while (AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) ; AscStopChip(iop_base); AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT); DvcSleepMilliSecond(200); - AscSetChipIH(iop_base, INS_RFLAG_WTM); AscSetChipIH(iop_base, INS_HALT); - AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT); AscSetChipControl(iop_base, CC_HALT); DvcSleepMilliSecond(200); + AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT); + AscSetChipStatus(iop_base, 0); return (AscIsChipHalted(iop_base)); } + + +ulong +AscGetMaxDmaCount( + ushort bus_type +) +{ + if (bus_type & ASC_IS_ISA) + return (ASC_MAX_ISA_DMA_COUNT); + else if (bus_type & (ASC_IS_EISA | ASC_IS_VL)) + return (ASC_MAX_VL_DMA_COUNT); + return (ASC_MAX_PCI_DMA_COUNT); +} + ushort AscGetIsaDmaChannel( PortAddr iop_base ) { ushort channel; - channel = AscGetChipCfgLsw(iop_base) & 0x0003; if (channel == 0x03) return (0); @@ -7612,9 +8427,7 @@ { ushort cfg_lsw; uchar value; - if ((dma_channel >= 5) && (dma_channel <= 7)) { - if (dma_channel == 7) value = 0x00; else @@ -7635,7 +8448,7 @@ { speed_value &= 0x07; AscSetBank(iop_base, 1); - AscSetChipDmaSpeed(iop_base, speed_value); + AscWriteChipDmaSpeed(iop_base, speed_value); AscSetBank(iop_base, 0); return (AscGetIsaDmaSpeed(iop_base)); } @@ -7646,45 +8459,38 @@ ) { uchar speed_value; - AscSetBank(iop_base, 1); - speed_value = AscGetChipDmaSpeed(iop_base); + speed_value = AscReadChipDmaSpeed(iop_base); speed_value &= 0x07; AscSetBank(iop_base, 0); return (speed_value); } -ulong -AscGetMaxDmaCount( - ushort bus_type -) -{ - if (bus_type & ASC_IS_ISA) - return (ASC_MAX_ISA_DMA_COUNT); - else if (bus_type & (ASC_IS_EISA | ASC_IS_VL)) - return (ASC_MAX_VL_DMA_COUNT); - return (ASC_MAX_PCI_DMA_COUNT); -} - ushort AscInitGetConfig( ASC_DVC_VAR asc_ptr_type * asc_dvc ) { ushort warn_code; - warn_code = 0; asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG; if (asc_dvc->err_code != 0) return (UW_ERR); if (AscFindSignature(asc_dvc->iop_base)) { warn_code |= AscInitAscDvcVar(asc_dvc); - warn_code |= AscInitFromEEP(asc_dvc); +#if CC_INCLUDE_EEP_CONFIG + if (asc_dvc->init_state & ASC_INIT_STATE_WITHOUT_EEP) { + warn_code |= AscInitWithoutEEP(asc_dvc); + } else { + warn_code |= AscInitFromEEP(asc_dvc); + } +#else + warn_code |= AscInitWithoutEEP(asc_dvc); +#endif asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG; - - if (asc_dvc->scsi_reset_wait > 10) - asc_dvc->scsi_reset_wait = 10; - + if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT) { + asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT; + } } else { asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE; } @@ -7697,7 +8503,6 @@ ) { ushort warn_code; - warn_code = 0; asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG; if (asc_dvc->err_code != 0) @@ -7712,53 +8517,124 @@ } ushort +AscInitFromAscDvcVar( + ASC_DVC_VAR asc_ptr_type * asc_dvc +) +{ + PortAddr iop_base; + ushort cfg_msw; + ushort warn_code; + ushort pci_device_id; + iop_base = asc_dvc->iop_base; + pci_device_id = asc_dvc->cfg->pci_device_id; + warn_code = 0; + cfg_msw = AscGetChipCfgMsw(iop_base); + if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) { + cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK)); + warn_code |= ASC_WARN_CFG_MSW_RECOVER; + AscSetChipCfgMsw(iop_base, cfg_msw); + } + if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) != + asc_dvc->cfg->cmd_qng_enabled) { + asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled; + warn_code |= ASC_WARN_CMD_QNG_CONFLICT; + } + if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) { + warn_code |= ASC_WARN_AUTO_CONFIG; + } + if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) { + if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type) + != asc_dvc->irq_no) { + asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO; + } + } + if (asc_dvc->bus_type & ASC_IS_PCI) { +#if CC_DISABLE_PCI_PARITY_INT + cfg_msw &= 0xFFC0; + AscSetChipCfgMsw(iop_base, cfg_msw); +#endif + if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) { + } else { + if ((pci_device_id == ASC_PCI_DEVICE_ID_REV_A) || + (pci_device_id == ASC_PCI_DEVICE_ID_REV_B)) { + asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB; + asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN; +#if CC_SET_PCI_LATENCY_TIMER_ZERO + DvcWritePCIConfigByte(asc_dvc, + AscPCIConfigCommandRegister, + AscPCICmdRegBits_BusMastering + ); + if ((DvcReadPCIConfigByte(asc_dvc, + AscPCIConfigCommandRegister + ) + & AscPCICmdRegBits_BusMastering) + != AscPCICmdRegBits_BusMastering) { + warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE; + } + DvcWritePCIConfigByte(asc_dvc, + AscPCIConfigLatencyTimer, + 0x00 + ); + if (DvcReadPCIConfigByte(asc_dvc, + AscPCIConfigLatencyTimer + ) != 0x00) { + warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE; + } +#endif + } + } + } else if (asc_dvc->bus_type == ASC_IS_ISAPNP) { + if (AscGetChipVersion(iop_base, asc_dvc->bus_type) + == ASC_CHIP_VER_ASYN_BUG) { + asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN; + } + } + if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) != + asc_dvc->cfg->chip_scsi_id) { + asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID; + } + if (asc_dvc->bus_type & ASC_IS_ISA) { + AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel); + AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed); + } + return (warn_code); +} + +ushort AscInitAsc1000Driver( ASC_DVC_VAR asc_ptr_type * asc_dvc ) { ushort warn_code; PortAddr iop_base; - extern ushort _mcode_size; extern ulong _mcode_chksum; extern uchar _mcode_buf[]; - - ASC_DBG(3, "AscInitAsc1000Driver: begin\n"); iop_base = asc_dvc->iop_base; warn_code = 0; - if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) && !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) { - - ASC_DBG(3, "AscInitAsc1000Driver: AscResetChipAndScsiBus()\n"); AscResetChipAndScsiBus(iop_base); DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000)); } asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC; if (asc_dvc->err_code != 0) return (UW_ERR); - ASC_DBG(3, "AscInitAsc1000Driver: AscFindSignature()\n"); if (!AscFindSignature(asc_dvc->iop_base)) { asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE; return (warn_code); } - ASC_DBG(3, "AscInitAsc1000Driver: AscDisableInterrupt()\n"); AscDisableInterrupt(iop_base); - - ASC_DBG(3, "AscInitAsc1000Driver: AscInitLram()\n"); warn_code |= AscInitLram(asc_dvc); if (asc_dvc->err_code != 0) return (UW_ERR); - ASC_DBG(3, "AscInitAsc1000Driver: AscLoadMicroCode()\n"); if (AscLoadMicroCode(iop_base, 0, (ushort dosfar *) _mcode_buf, _mcode_size) != _mcode_chksum) { asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM; return (warn_code); } - ASC_DBG(3, "AscInitAsc1000Driver: AscInitMicroCodeVar()\n"); warn_code |= AscInitMicroCodeVar(asc_dvc); asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC; - ASC_DBG(3, "AscInitAsc1000Driver: AscEnableInterrupt()\n"); AscEnableInterrupt(iop_base); return (warn_code); } @@ -7771,121 +8647,111 @@ int i; PortAddr iop_base; ushort warn_code; - + uchar chip_version; iop_base = asc_dvc->iop_base; warn_code = 0; asc_dvc->err_code = 0; - - if ((asc_dvc->bus_type & - (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0) { + if ( + (asc_dvc->bus_type & + (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0 + ) { asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE; } + AscSetChipControl(iop_base, CC_HALT); + AscSetChipStatus(iop_base, 0); #if CC_LINK_BUSY_Q for (i = 0; i <= ASC_MAX_TID; i++) { asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q dosfar *) 0L; asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q dosfar *) 0L; } #endif - - asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL; asc_dvc->bug_fix_cntl = 0; asc_dvc->pci_fix_asyn_xfer = 0; - asc_dvc->init_sdtr = 0; + asc_dvc->pci_fix_asyn_xfer_always = 0; + asc_dvc->init_state = 0; asc_dvc->sdtr_done = 0; - asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG; asc_dvc->cur_total_qng = 0; asc_dvc->is_in_int = 0; - asc_dvc->scsi_reset_wait = 3; asc_dvc->in_critical_cnt = 0; - asc_dvc->last_q_shortage = 0; asc_dvc->use_tagged_qng = 0; - asc_dvc->cfg->can_tagged_qng = 0; asc_dvc->no_scam = 0; - asc_dvc->irq_no = 10; - asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET; - asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET; - asc_dvc->cfg->cmd_qng_enabled = ASC_SCSI_WIDTH_BIT_SET; - asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID; - asc_dvc->cfg->chip_version = AscGetChipVersion(iop_base, - asc_dvc->bus_type); - if (AscGetChipBusType(iop_base) == ASC_IS_ISAPNP) { - - AscPutChipIFC(iop_base, IFC_INIT_DEFAULT); - asc_dvc->bus_type = ASC_IS_ISAPNP; - } asc_dvc->unit_not_ready = 0; asc_dvc->queue_full_or_busy = 0; - - if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) { - asc_dvc->cfg->isa_dma_channel = (uchar) AscGetIsaDmaChannel(iop_base); - asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED; - } - asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER; - asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) | - ASC_LIB_VERSION_MINOR; - asc_dvc->int_count = 0L; - asc_dvc->req_count = 0L; - asc_dvc->busy_count = 0L; - asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type); - - for (i = 0; i <= ASC_MAX_TID; i++) { - asc_dvc->cfg->sdtr_data[i] = - (uchar) (ASC_DEF_SDTR_OFFSET | (ASC_DEF_SDTR_INDEX << 4)); - asc_dvc->cur_dvc_qng[i] = 0; - asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG; - asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q dosfar *) 0L; - asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q dosfar *) 0L; - } - return (warn_code); -} - -ushort -AscInitFromAscDvcVar( - ASC_DVC_VAR asc_ptr_type * asc_dvc -) -{ - PortAddr iop_base; - ushort cfg_msw; - ushort warn_code; - - iop_base = asc_dvc->iop_base; - warn_code = 0; - - cfg_msw = AscGetChipCfgMsw(iop_base); - - if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) { - cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK)); - warn_code |= ASC_WARN_CFG_MSW_RECOVER; - AscSetChipCfgMsw(iop_base, cfg_msw); - } - if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) { - warn_code |= ASC_WARN_AUTO_CONFIG; - - } - if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) != - asc_dvc->cfg->cmd_qng_enabled) { - asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled; - warn_code |= ASC_WARN_CMD_QNG_CONFLICT; - } - if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) { - - if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type) - != asc_dvc->irq_no) { - asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO; - } + asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL; + asc_dvc->init_sdtr = ASC_SCSI_WIDTH_BIT_SET; + asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG; + asc_dvc->scsi_reset_wait = 3; + asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET; + asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type); + asc_dvc->redo_scam = 0; + asc_dvc->res2 = 0; + asc_dvc->res4 = 0; + asc_dvc->res6 = 0; + asc_dvc->res7 = 0; + asc_dvc->res8 = 0; + asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET; + asc_dvc->cfg->can_tagged_qng = 0; + asc_dvc->cfg->cmd_qng_enabled = 0; + asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID; + asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER; + asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) | + ASC_LIB_VERSION_MINOR; + chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type); + asc_dvc->cfg->chip_version = chip_version; + asc_dvc->sdtr_period_tbl[0] = SYN_XFER_NS_0; + asc_dvc->sdtr_period_tbl[1] = SYN_XFER_NS_1; + asc_dvc->sdtr_period_tbl[2] = SYN_XFER_NS_2; + asc_dvc->sdtr_period_tbl[3] = SYN_XFER_NS_3; + asc_dvc->sdtr_period_tbl[4] = SYN_XFER_NS_4; + asc_dvc->sdtr_period_tbl[5] = SYN_XFER_NS_5; + asc_dvc->sdtr_period_tbl[6] = SYN_XFER_NS_6; + asc_dvc->sdtr_period_tbl[7] = SYN_XFER_NS_7; + asc_dvc->max_sdtr_index = 7; + if ( + (asc_dvc->bus_type & ASC_IS_PCI) && + (chip_version >= ASC_CHIP_VER_1ST_PCI_ULTRA) + ) { + asc_dvc->sdtr_period_tbl[0] = SYN_ULTRA_XFER_NS_0; + asc_dvc->sdtr_period_tbl[1] = SYN_ULTRA_XFER_NS_1; + asc_dvc->sdtr_period_tbl[2] = SYN_ULTRA_XFER_NS_2; + asc_dvc->sdtr_period_tbl[3] = SYN_ULTRA_XFER_NS_3; + asc_dvc->sdtr_period_tbl[4] = SYN_ULTRA_XFER_NS_4; + asc_dvc->sdtr_period_tbl[5] = SYN_ULTRA_XFER_NS_5; + asc_dvc->sdtr_period_tbl[6] = SYN_ULTRA_XFER_NS_6; + asc_dvc->sdtr_period_tbl[7] = SYN_ULTRA_XFER_NS_7; + asc_dvc->sdtr_period_tbl[8] = SYN_ULTRA_XFER_NS_8; + asc_dvc->sdtr_period_tbl[9] = SYN_ULTRA_XFER_NS_9; + asc_dvc->sdtr_period_tbl[10] = SYN_ULTRA_XFER_NS_10; + asc_dvc->sdtr_period_tbl[11] = SYN_ULTRA_XFER_NS_11; + asc_dvc->sdtr_period_tbl[12] = SYN_ULTRA_XFER_NS_12; + asc_dvc->sdtr_period_tbl[13] = SYN_ULTRA_XFER_NS_13; + asc_dvc->sdtr_period_tbl[14] = SYN_ULTRA_XFER_NS_14; + asc_dvc->sdtr_period_tbl[15] = SYN_ULTRA_XFER_NS_15; + asc_dvc->max_sdtr_index = 15; + AscSetExtraControl(iop_base, (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE)); + asc_dvc->bus_type = ASC_IS_PCI_ULTRA; } - if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) != - asc_dvc->cfg->chip_scsi_id) { - asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID; + asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED; + if (AscGetChipBusType(iop_base) == ASC_IS_ISAPNP) { + AscSetChipIFC(iop_base, IFC_INIT_DEFAULT); + asc_dvc->bus_type = ASC_IS_ISAPNP; } if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) { - AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel); - AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed); + asc_dvc->cfg->isa_dma_channel = (uchar) AscGetIsaDmaChannel(iop_base); + } + for (i = 0; i <= ASC_MAX_TID; i++) { + asc_dvc->cur_dvc_qng[i] = 0; + asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG; + asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q dosfar *) 0L; + asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q dosfar *) 0L; + asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG; + asc_dvc->cfg->sdtr_period_offset[i] = (uchar) (ASC_DEF_SDTR_OFFSET | (ASC_DEF_SDTR_INDEX << 4)); } return (warn_code); } +#if CC_INCLUDE_EEP_CONFIG ushort AscInitFromEEP( ASC_DVC_VAR asc_ptr_type * asc_dvc @@ -7897,13 +8763,10 @@ ushort chksum; ushort warn_code; ushort cfg_msw, cfg_lsw; - uchar i; - + int i; iop_base = asc_dvc->iop_base; warn_code = 0; - AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE); - AscStopQueueExe(iop_base); if ((AscStopChip(iop_base) == FALSE) || (AscGetChipScsiCtrl(iop_base) != 0)) { @@ -7921,33 +8784,18 @@ return (warn_code); } eep_config = (ASCEEP_CONFIG dosfar *) & eep_config_buf; - cfg_msw = AscGetChipCfgMsw(iop_base); cfg_lsw = AscGetChipCfgLsw(iop_base); - - if (asc_dvc->bus_type & ASC_IS_PCI) { -#if CC_DISABLE_PCI_PARITY_INT - cfg_msw &= 0xFFC0; - AscSetChipCfgMsw(iop_base, cfg_msw); -#endif - if (asc_dvc->cfg->pci_device_id == ASC_PCI_DEVICE_ID_REV_A) { - asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ADD_ONE_BYTE; - } - } if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) { cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK)); warn_code |= ASC_WARN_CFG_MSW_RECOVER; AscSetChipCfgMsw(iop_base, cfg_msw); } chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type); - eep_config->cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK)); - if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) { warn_code |= ASC_WARN_AUTO_CONFIG; - if (asc_dvc->cfg->chip_version == 3) { - if (eep_config->cfg_lsw != cfg_lsw) { warn_code |= ASC_WARN_EEPROM_RECOVER; eep_config->cfg_lsw = AscGetChipCfgLsw(iop_base); @@ -7964,28 +8812,18 @@ } asc_dvc->init_sdtr = eep_config->init_sdtr; asc_dvc->cfg->disc_enable = eep_config->disc_enable; - asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng; asc_dvc->cfg->isa_dma_speed = eep_config->isa_dma_speed; asc_dvc->start_motor = eep_config->start_motor; asc_dvc->dvc_cntl = eep_config->cntl; asc_dvc->no_scam = eep_config->no_scam; - - if ((asc_dvc->bus_type & ASC_IS_PCI) && - !(asc_dvc->dvc_cntl & ASC_CNTL_NO_PCI_FIX_ASYN_XFER)) { - if ((asc_dvc->cfg->pci_device_id == ASC_PCI_DEVICE_ID_REV_A) || - (asc_dvc->cfg->pci_device_id == ASC_PCI_DEVICE_ID_REV_B)) { - asc_dvc->pci_fix_asyn_xfer = ASC_ALL_DEVICE_BIT_SET; - } - } else if ((asc_dvc->bus_type & ASC_IS_ISAPNP) == ASC_IS_ISAPNP) { - - if (AscGetChipVersion(iop_base, asc_dvc->bus_type) - == ASC_CHIP_VER_ASYN_BUG) { - asc_dvc->pci_fix_asyn_xfer = ASC_ALL_DEVICE_BIT_SET; - } - } if (!AscTestExternalLram(asc_dvc)) { - if (asc_dvc->bus_type & ASC_IS_PCI) { + if ( + ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) + ) { + eep_config->max_total_qng = ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG; + eep_config->max_tag_qng = ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG; + } else { eep_config->cfg_msw |= 0x0800; cfg_msw |= 0x0800; AscSetChipCfgMsw(iop_base, cfg_msw); @@ -7993,9 +8831,6 @@ eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG; } } else { -#if CC_TEST_RW_LRAM - asc_dvc->err_code |= AscTestLramEndian(iop_base); -#endif } if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) { eep_config->max_total_qng = ASC_MIN_TOTAL_QNG; @@ -8010,25 +8845,60 @@ eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC; } asc_dvc->max_total_qng = eep_config->max_total_qng; - if ((eep_config->use_cmd_qng & eep_config->disc_enable) != eep_config->use_cmd_qng) { eep_config->disc_enable = eep_config->use_cmd_qng; warn_code |= ASC_WARN_CMD_QNG_CONFLICT; } - asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type); + if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) { + asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type); + } eep_config->chip_scsi_id &= ASC_MAX_TID; asc_dvc->cfg->chip_scsi_id = eep_config->chip_scsi_id; - for (i = 0; i <= ASC_MAX_TID; i++) { - asc_dvc->cfg->sdtr_data[i] = eep_config->sdtr_data[i]; +#if CC_TMP_USE_EEP_SDTR + asc_dvc->cfg->sdtr_period_offset[i] = eep_config->dos_int13_table[i]; +#endif + asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i]; asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng; } - eep_config->cfg_msw = AscGetChipCfgMsw(iop_base); +#if CC_CHK_FIX_EEP_CONTENT if (AscSetEEPConfig(iop_base, eep_config, asc_dvc->bus_type) != 0) { asc_dvc->err_code |= ASC_IERR_WRITE_EEPROM; } +#endif + return (warn_code); +} +#endif + +ushort +AscInitWithoutEEP( + ASC_DVC_VAR asc_ptr_type * asc_dvc +) +{ + PortAddr iop_base; + ushort warn_code; + ushort cfg_msw; + iop_base = asc_dvc->iop_base; + warn_code = 0; + cfg_msw = AscGetChipCfgMsw(iop_base); + if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) { + cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK)); + warn_code |= ASC_WARN_CFG_MSW_RECOVER; + AscSetChipCfgMsw(iop_base, cfg_msw); + } + if (!AscTestExternalLram(asc_dvc)) { + if (asc_dvc->bus_type & ASC_IS_PCI) { + cfg_msw |= 0x0800; + AscSetChipCfgMsw(iop_base, cfg_msw); + asc_dvc->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG; + } + } else { + } + if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) { + asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type); + } return (warn_code); } @@ -8041,16 +8911,14 @@ ushort warn_code; PortAddr iop_base; ulong phy_addr; - iop_base = asc_dvc->iop_base; warn_code = 0; for (i = 0; i <= ASC_MAX_TID; i++) { - AscWriteLramByte(iop_base, (ushort) (ASCV_SDTR_DATA_BEG + i), - asc_dvc->cfg->sdtr_data[i]); + AscPutMCodeInitSDTRAtID(iop_base, i, + asc_dvc->cfg->sdtr_period_offset[i] + ); } - AscInitQLinkVar(asc_dvc); - AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B, asc_dvc->cfg->disc_enable); AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B, @@ -8060,13 +8928,11 @@ ASC_OVERRUN_BSIZE)) == 0L) { asc_dvc->err_code |= ASC_IERR_GET_PHY_ADDR; } else { - phy_addr = (phy_addr & 0xFFFFFFF8UL) + 8; AscWriteLramDWord(iop_base, ASCV_OVERRUN_PADDR_D, phy_addr); AscWriteLramDWord(iop_base, ASCV_OVERRUN_BSIZE_D, ASC_OVERRUN_BSIZE - 8); } - asc_dvc->cfg->mcode_date = AscReadLramWord(iop_base, (ushort) ASCV_MC_DATE_W); asc_dvc->cfg->mcode_version = AscReadLramWord(iop_base, @@ -8093,11 +8959,8 @@ ASC_ISR_CALLBACK asc_isr_callback; uchar cp_sen_len; uchar i; - if ((scsi_done_q->d2.flag & ASC_FLAG_SCSIQ_REQ) != 0) { scsiq_req = (ASC_SCSI_REQ_Q dosfar *) scsi_done_q->d2.srb_ptr; - ASC_DBG2(3, "AscInitPollIsrCallBack: done_stat %x, host_stat %x\n", - scsiq_req->r3.done_stat, scsiq_req->r3.host_stat); scsiq_req->r3.done_stat = scsi_done_q->d3.done_stat; scsiq_req->r3.host_stat = scsi_done_q->d3.host_stat; scsiq_req->r3.scsi_stat = scsi_done_q->d3.scsi_stat; @@ -8113,8 +8976,6 @@ } } } else { - ASC_DBG1(3, "AscInitPollIsrCallBack: isr_callback %x\n", - (unsigned) asc_dvc->isr_callback); if (asc_dvc->isr_callback != 0) { asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback; (*asc_isr_callback) (asc_dvc, scsi_done_q); @@ -8132,23 +8993,22 @@ ushort q_addr; ushort saved_word; int sta; - iop_base = asc_dvc->iop_base; sta = 0; - q_addr = ASC_QNO_TO_QADDR(241); saved_word = AscReadLramWord(iop_base, q_addr); - if (AscVerWriteLramWord(iop_base, q_addr, 0x55AA) == 0) { + AscSetChipLramAddr(iop_base, q_addr); + AscSetChipLramData(iop_base, 0x55AA); + DvcSleepMilliSecond(10); + AscSetChipLramAddr(iop_base, q_addr); + if (AscGetChipLramData(iop_base) == 0x55AA) { sta = 1; AscWriteLramWord(iop_base, q_addr, saved_word); } return (sta); } -#if CC_TEST_LRAM_ENDIAN - -#endif - +#if CC_INCLUDE_EEP_CONFIG int AscWriteEEPCmdReg( PortAddr iop_base, @@ -8157,7 +9017,6 @@ { uchar read_back; int retry; - retry = 0; while (TRUE) { AscSetChipEEPCmd(iop_base, cmd_reg); @@ -8180,7 +9039,6 @@ { ushort read_back; int retry; - retry = 0; while (TRUE) { AscSetChipEEPData(iop_base, data_reg); @@ -8221,7 +9079,6 @@ { ushort read_wval; uchar cmd_reg; - AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE); AscWaitEEPRead(); cmd_reg = addr | ASC_EEP_CMD_READ; @@ -8240,19 +9097,15 @@ ) { ushort read_wval; - read_wval = AscReadEEPWord(iop_base, addr); if (read_wval != word_val) { AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE); AscWaitEEPRead(); - AscWriteEEPDataReg(iop_base, word_val); AscWaitEEPRead(); - AscWriteEEPCmdReg(iop_base, (uchar) ((uchar) ASC_EEP_CMD_WRITE | addr)); AscWaitEEPWrite(); - AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE); AscWaitEEPRead(); return (AscReadEEPWord(iop_base, addr)); @@ -8273,17 +9126,14 @@ int cfg_end; int s_addr; int isa_pnp_wsize; - wbuf = (ushort dosfar *) cfg_buf; sum = 0; - isa_pnp_wsize = 0; for (s_addr = 0; s_addr < (2 + isa_pnp_wsize); s_addr++, wbuf++) { wval = AscReadEEPWord(iop_base, (uchar) s_addr); sum += wval; *wbuf = wval; } - if (bus_type & ASC_IS_VL) { cfg_beg = ASC_EEP_DVC_CFG_BEG_VL; cfg_end = ASC_EEP_MAX_DVC_ADDR_VL; @@ -8291,7 +9141,6 @@ cfg_beg = ASC_EEP_DVC_CFG_BEG; cfg_end = ASC_EEP_MAX_DVC_ADDR; } - for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) { wval = AscReadEEPWord(iop_base, (uchar) s_addr); @@ -8302,6 +9151,7 @@ return (sum); } +#if CC_CHK_FIX_EEP_CONTENT int AscSetEEPConfigOnce( PortAddr iop_base, @@ -8314,7 +9164,6 @@ int s_addr; int cfg_beg; int cfg_end; - wbuf = (ushort dosfar *) cfg_buf; n_error = 0; sum = 0; @@ -8365,7 +9214,6 @@ { int retry; int n_error; - retry = 0; while (TRUE) { if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf, @@ -8378,24 +9226,21 @@ } return (n_error); } +#endif +#endif int AscInitPollBegin( - ASC_DVC_VAR asc_ptr_type * asc_dvc + REG ASC_DVC_VAR asc_ptr_type * asc_dvc ) { PortAddr iop_base; - iop_base = asc_dvc->iop_base; - #if CC_INIT_INQ_DISPLAY DvcDisplayString((uchar dosfar *) "\r\n"); #endif - AscDisableInterrupt(iop_base); - asc_dvc->init_state |= ASC_INIT_STATE_BEG_INQUIRY; - AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B, 0x00); asc_dvc->use_tagged_qng = 0; asc_dvc->cfg->can_tagged_qng = 0; @@ -8406,12 +9251,11 @@ int AscInitPollEnd( - ASC_DVC_VAR asc_ptr_type * asc_dvc + REG ASC_DVC_VAR asc_ptr_type * asc_dvc ) { PortAddr iop_base; - int i; - + rint i; iop_base = asc_dvc->iop_base; asc_dvc->isr_callback = (Ptr2Func) asc_dvc->saved_ptr2func; AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B, @@ -8420,20 +9264,17 @@ asc_dvc->use_tagged_qng); AscWriteLramByte(iop_base, ASCV_CAN_TAGGED_QNG_B, asc_dvc->cfg->can_tagged_qng); - for (i = 0; i <= ASC_MAX_TID; i++) { AscWriteLramByte(iop_base, (ushort) ((ushort) ASCV_MAX_DVC_QNG_BEG + (ushort) i), asc_dvc->max_dvc_qng[i]); } - + AscAckInterrupt(iop_base); AscEnableInterrupt(iop_base); - #if CC_INIT_INQ_DISPLAY DvcDisplayString((uchar dosfar *) "\r\n"); #endif asc_dvc->init_state |= ASC_INIT_STATE_END_INQUIRY; - return (0); } @@ -8441,10 +9282,10 @@ int AscInitPollTarget( - ASC_DVC_VAR asc_ptr_type * asc_dvc, - ASC_SCSI_REQ_Q dosfar * scsiq, - ASC_SCSI_INQUIRY dosfar * inq, - ASC_CAP_INFO dosfar * cap_info + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_REQ_Q dosfar * scsiq, + REG ASC_SCSI_INQUIRY dosfar * inq, + REG ASC_CAP_INFO dosfar * cap_info ) { uchar tid_no, lun; @@ -8453,42 +9294,49 @@ int dvc_found; int support_read_cap; int tmp_disable_init_sdtr; + int sta; ulong phy_addr; - dvc_found = 0; tmp_disable_init_sdtr = FALSE; tid_bits = scsiq->r1.target_id; lun = scsiq->r1.target_lun; tid_no = ASC_TIX_TO_TID(scsiq->r2.target_ix); - if ((phy_addr = AscGetOnePhyAddr(asc_dvc, - (uchar dosfar *) scsiq->sense_ptr, - (ulong) scsiq->r1.sense_len)) == 0L) { + if ( + (phy_addr = AscGetOnePhyAddr(asc_dvc, + (uchar dosfar *) scsiq->sense_ptr, + (ulong) scsiq->r1.sense_len)) == 0L + ) { return (ERR); } scsiq->r1.sense_addr = phy_addr; - if (((asc_dvc->init_sdtr & tid_bits) != 0) && - ((asc_dvc->sdtr_done & tid_bits) == 0)) { - + if ( + ((asc_dvc->init_sdtr & tid_bits) != 0) + && ((asc_dvc->sdtr_done & tid_bits) == 0) + ) { asc_dvc->init_sdtr &= ~tid_bits; tmp_disable_init_sdtr = TRUE; } - ASC_DBG(3, "AscInitPollTarget: PollScsiInquiry()\n"); - if (PollScsiInquiry(asc_dvc, scsiq, (uchar dosfar *) inq, - sizeof (ASC_SCSI_INQUIRY)) == 1) { + if ( + PollScsiInquiry(asc_dvc, scsiq, (uchar dosfar *) inq, + sizeof (ASC_SCSI_INQUIRY)) == 1 + ) { dvc_found = 1; support_read_cap = TRUE; dvc_type = inq->byte0.peri_dvc_type; if (dvc_type != SCSI_TYPE_UNKNOWN) { - if ((dvc_type != SCSI_TYPE_DASD) && - (dvc_type != SCSI_TYPE_WORM) && - (dvc_type != SCSI_TYPE_CDROM) && - (dvc_type != SCSI_TYPE_OPTMEM)) { + if ( + (dvc_type != SCSI_TYPE_DASD) + && (dvc_type != SCSI_TYPE_WORM) + && (dvc_type != SCSI_TYPE_CDROM) + && (dvc_type != SCSI_TYPE_OPTMEM) + ) { asc_dvc->start_motor &= ~tid_bits; support_read_cap = FALSE; } - if ((dvc_type != SCSI_TYPE_DASD) || - inq->byte1.rmb) { - + if ( + (dvc_type != SCSI_TYPE_DASD) + || inq->byte1.rmb + ) { if (!_asc_wait_slow_device_) { DvcSleepMilliSecond(3000 - ((int) tid_no * 250)); _asc_wait_slow_device_ = TRUE; @@ -8497,105 +9345,105 @@ #if CC_INIT_INQ_DISPLAY AscDispInquiry(tid_no, lun, inq); #endif - - ASC_DBG_PRT_INQUIRY(2, inq, sizeof(ASC_SCSI_INQUIRY)); - if (lun == 0) { - - ASC_DBG1(2, "AscInitPollTarget: vendor_id: \"%.8s\"\n", - inq->vendor_id); - ASC_DBG1(2, "AscInitPollTarget: product_id: \"%.16s\"\n", - inq->product_id); - ASC_DBG1(2, "AscInitPollTarget: product_rev_level: \"%.4s\"\n", - inq->product_rev_level); - - ASC_DBG1(2, "AscInitPollTarget: byte3.rsp_data_fmt %x\n", - inq->byte3.rsp_data_fmt); - ASC_DBG1(2, "AscInitPollTarget: byte3.ansi_apr_ver %x\n", - inq->byte2.ansi_apr_ver); - - if ((inq->byte3.rsp_data_fmt >= 2) || - (inq->byte2.ansi_apr_ver >= 2)) { - - ASC_DBG1(2, "AscInitPollTarget: byte7.CmdQue %x\n", - inq->byte7.CmdQue); - + if ( + (inq->byte3.rsp_data_fmt >= 2) + || (inq->byte2.ansi_apr_ver >= 2) + ) { if (inq->byte7.CmdQue) { asc_dvc->cfg->can_tagged_qng |= tid_bits; if (asc_dvc->cfg->cmd_qng_enabled & tid_bits) { - asc_dvc->use_tagged_qng |= tid_bits; - asc_dvc->max_dvc_qng[tid_no] = - asc_dvc->cfg->max_tag_qng[tid_no]; +#if CC_FIX_QUANTUM_XP34301_1071 + if ( + (inq->add_len >= 32) + && (AscCompareString(inq->vendor_id, (uchar *) "QUANTUM XP34301", 15) == 0) + && (AscCompareString(inq->product_rev_level, (uchar *) "1071", 4) == 0) + ) { + } else { +#endif + asc_dvc->use_tagged_qng |= tid_bits; + asc_dvc->max_dvc_qng[tid_no] = asc_dvc->cfg->max_tag_qng[tid_no]; +#if CC_FIX_QUANTUM_XP34301_1071 + } +#endif } } - ASC_DBG1(2, "AscInitPollTarget: byte7.Sync %x\n", - inq->byte7.Sync); - if (!inq->byte7.Sync) { - asc_dvc->init_sdtr &= ~tid_bits; asc_dvc->sdtr_done &= ~tid_bits; } else if (tmp_disable_init_sdtr) { - asc_dvc->init_sdtr |= tid_bits; } } else { - asc_dvc->init_sdtr &= ~tid_bits; asc_dvc->sdtr_done &= ~tid_bits; asc_dvc->use_tagged_qng &= ~tid_bits; } } - if (asc_dvc->pci_fix_asyn_xfer & tid_bits) { + if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN) { if (!(asc_dvc->init_sdtr & tid_bits)) { - - AscSetRunChipSynRegAtID(asc_dvc->iop_base, tid_no, - ASYN_SDTR_DATA_FIX_PCI_REV_AB); + if ( + (dvc_type == SCSI_TYPE_CDROM) + && (AscCompareString((uchar *) inq->vendor_id, (uchar *) "HP ", 3) == 0) + ) { + asc_dvc->pci_fix_asyn_xfer_always |= tid_bits; + } + asc_dvc->pci_fix_asyn_xfer |= tid_bits; +#if CC_DISABLE_ASYN_FIX_WANGTEK_TAPE + if ( + (dvc_type == SCSI_TYPE_SASD) + && (AscCompareString((uchar *) inq->vendor_id, (uchar *) "WANGTEK ", 8) == 0) + ) { + asc_dvc->pci_fix_asyn_xfer &= ~tid_bits; + } +#endif + if (asc_dvc->pci_fix_asyn_xfer & tid_bits) { + AscSetRunChipSynRegAtID(asc_dvc->iop_base, tid_no, + ASYN_SDTR_DATA_FIX_PCI_REV_AB); + } } } - ASC_DBG(3, "AscInitPollTarget: InitTestUnitReady()\n"); - if (InitTestUnitReady(asc_dvc, scsiq) != 1) { - - } else { + sta = 1; +#if CC_INIT_TARGET_TEST_UNIT_READY + sta = InitTestUnitReady(asc_dvc, scsiq); +#endif +#if CC_INIT_TARGET_READ_CAPACITY + if (sta == 1) { if ((cap_info != 0L) && support_read_cap) { - ASC_DBG(3, "AscInitPollTarget: PollScsiReadCapacity()\n"); if (PollScsiReadCapacity(asc_dvc, scsiq, cap_info) != 1) { cap_info->lba = 0L; cap_info->blk_size = 0x0000; } else { - } } } +#endif } else { asc_dvc->start_motor &= ~tid_bits; } } else { - } return (dvc_found); } int PollQueueDone( - ASC_DVC_VAR asc_ptr_type * asc_dvc, - ASC_SCSI_REQ_Q dosfar * scsiq, + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_REQ_Q dosfar * scsiq, int timeout_sec ) { int status; int retry; - retry = 0; do { - ASC_DBG(3, "PollQueueDone: AscExeScsiQueue()\n"); - if ((status = AscExeScsiQueue(asc_dvc, - (ASC_SCSI_Q dosfar *) scsiq)) == 1) { - ASC_DBG(3, "PollQueueDone: AscPollQDone()\n"); + if ( + (status = AscExeScsiQueue(asc_dvc, + (ASC_SCSI_Q dosfar *) scsiq)) == 1 + ) { if ((status = AscPollQDone(asc_dvc, scsiq, timeout_sec)) != 1) { - ASC_DBG1(3, "PollQueueDone: AscPollQDone() status %x\n", status); if (status == 0x80) { if (retry++ > ASC_MAX_INIT_BUSY_RETRY) { break; @@ -8604,30 +9452,25 @@ scsiq->r3.host_stat = 0; scsiq->r3.scsi_stat = 0; scsiq->r3.scsi_msg = 0; - DvcSleepMilliSecond(100); + DvcSleepMilliSecond(2000); continue; } scsiq->r3.done_stat = 0; scsiq->r3.host_stat = 0; scsiq->r3.scsi_stat = 0; scsiq->r3.scsi_msg = 0; - ASC_DBG1(3, "PollQueueDone: AscAbortSRB() scsiq %x\n", - (unsigned) scsiq); - AscAbortSRB(asc_dvc, (ulong) scsiq); } - ASC_DBG1(3, "PollQueueDone: done_stat %x\n", scsiq->r3.done_stat); return (scsiq->r3.done_stat); } } while ((status == 0) || (status == 0x80)); - ASC_DBG(3, "PollQueueDone: done_stat QD_WITH_ERROR\n"); return (scsiq->r3.done_stat = QD_WITH_ERROR); } int PollScsiInquiry( - ASC_DVC_VAR asc_ptr_type * asc_dvc, - ASC_SCSI_REQ_Q dosfar * scsiq, + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_REQ_Q dosfar * scsiq, uchar dosfar * buf, int buf_len ) @@ -8638,16 +9481,30 @@ return (PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q dosfar *) scsiq, 4)); } +#if CC_INIT_TARGET_START_UNIT +int +PollScsiStartUnit( + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_REQ_Q dosfar * scsiq +) +{ + if (AscScsiStartStopUnit(asc_dvc, scsiq, 1) == ERR) { + return (scsiq->r3.done_stat = QD_WITH_ERROR); + } + return (PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q dosfar *) scsiq, 40)); +} +#endif + +#if CC_INIT_TARGET_READ_CAPACITY int PollScsiReadCapacity( - ASC_DVC_VAR asc_ptr_type * asc_dvc, - ASC_SCSI_REQ_Q dosfar * scsiq, - ASC_CAP_INFO dosfar * cap_info + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_REQ_Q dosfar * scsiq, + REG ASC_CAP_INFO dosfar * cap_info ) { ASC_CAP_INFO scsi_cap_info; int status; - if (AscScsiReadCapacity(asc_dvc, scsiq, (uchar dosfar *) & scsi_cap_info) == ERR) { return (scsiq->r3.done_stat = QD_WITH_ERROR); @@ -8665,6 +9522,7 @@ } return (scsiq->r3.done_stat = QD_WITH_ERROR); } +#endif ulong dosfar * swapfarbuf4( @@ -8684,10 +9542,11 @@ return ((ulong dosfar *) buf); } +#if CC_INIT_TARGET_TEST_UNIT_READY int PollScsiTestUnitReady( - ASC_DVC_VAR asc_ptr_type * asc_dvc, - ASC_SCSI_REQ_Q dosfar * scsiq + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_REQ_Q dosfar * scsiq ) { if (AscScsiTestUnitReady(asc_dvc, scsiq) == ERR) { @@ -8697,45 +9556,26 @@ } int -PollScsiStartUnit( - ASC_DVC_VAR asc_ptr_type * asc_dvc, - ASC_SCSI_REQ_Q dosfar * scsiq -) -{ - if (AscScsiStartStopUnit(asc_dvc, scsiq, 1) == ERR) { - return (scsiq->r3.done_stat = QD_WITH_ERROR); - } - return (PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q dosfar *) scsiq, 40)); -} - -int InitTestUnitReady( - ASC_DVC_VAR asc_ptr_type * asc_dvc, - ASC_SCSI_REQ_Q dosfar * scsiq + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_REQ_Q dosfar * scsiq ) { ASC_SCSI_BIT_ID_TYPE tid_bits; int retry; ASC_REQ_SENSE dosfar *sen; - retry = 0; tid_bits = scsiq->r1.target_id; while (retry++ < 2) { - ASC_DBG(3, "InitTestUnitReady: PollScsiTestUnitReady()\n"); PollScsiTestUnitReady(asc_dvc, scsiq); - ASC_DBG1(3, "InitTestUnitReady: done_stat %x\n", scsiq->r3.done_stat); if (scsiq->r3.done_stat == 0x01) { return (1); } else if (scsiq->r3.done_stat == QD_WITH_ERROR) { DvcSleepMilliSecond(100); - sen = (ASC_REQ_SENSE dosfar *) scsiq->sense_ptr; - if ((scsiq->r3.scsi_stat == SS_CHK_CONDITION) && ((sen->err_code & 0x70) != 0)) { - if (sen->sense_key == SCSI_SENKEY_NOT_READY) { - if (asc_dvc->start_motor & tid_bits) { if (PollScsiStartUnit(asc_dvc, scsiq) == 1) { retry = 0; @@ -8745,10 +9585,10 @@ break; } } else { - DvcSleepMilliSecond(100); + DvcSleepMilliSecond(5000); } } else if (sen->sense_key == SCSI_SENKEY_ATTENSION) { - DvcSleepMilliSecond(100); + DvcSleepMilliSecond(500); } else { break; } @@ -8763,31 +9603,23 @@ } return (0); } - -#if CC_INIT_INQ_DISPLAY - #endif int AscPollQDone( - ASC_DVC_VAR asc_ptr_type * asc_dvc, - ASC_SCSI_REQ_Q dosfar * scsiq, + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_REQ_Q dosfar * scsiq, int timeout_sec ) { int loop, loop_end; int sta; PortAddr iop_base; - iop_base = asc_dvc->iop_base; loop = 0; loop_end = timeout_sec * 100; sta = 1; - while (TRUE) { - ASC_DBG4(3, - "AscPollQDone: loop %d, err_code %x, done_stat %x, scsi_stat %x\n", - loop, asc_dvc->err_code, scsiq->r3.done_stat, scsiq->r3.scsi_stat); if (asc_dvc->err_code != 0) { scsiq->r3.done_stat = QD_WITH_ERROR; sta = ERR; @@ -8797,7 +9629,6 @@ if ((scsiq->r3.done_stat == QD_WITH_ERROR) && (scsiq->r3.scsi_stat == SS_TARGET_BUSY)) { sta = 0x80; - break; } break; } @@ -8807,20 +9638,40 @@ break; } if (AscIsChipHalted(iop_base)) { +#if !CC_ASCISR_CHECK_INT_PENDING + AscAckInterrupt(iop_base); +#endif AscISR(asc_dvc); loop = 0; } else { - ASC_DBG(3, "AscPollQDone: AscIsIntPending()\n"); if (AscIsIntPending(iop_base)) { - ASC_DBG(3, "AscPollQDone: AscISR()\n"); +#if !CC_ASCISR_CHECK_INT_PENDING + AscAckInterrupt(iop_base); +#endif AscISR(asc_dvc); } } } - ASC_DBG1(3, "AscPollQDone: sta %x\n", sta); return (sta); } +int +AscCompareString( + ruchar * str1, + ruchar * str2, + int len +) +{ + int i; + int diff; + for (i = 0; i < len; i++) { + diff = (int) (str1[i] - str2[i]); + if (diff != 0) + return (diff); + } + return (0); +} + uchar AscReadLramByte( PortAddr iop_base, @@ -8829,27 +9680,14 @@ { uchar byte_data; ushort word_data; - if (isodd_word(addr)) { AscSetChipLramAddr(iop_base, addr - 1); word_data = AscGetChipLramData(iop_base); - -#if CC_LITTLE_ENDIAN_HOST byte_data = (uchar) ((word_data >> 8) & 0xFF); -#else - byte_data = (uchar) (word_data & 0xFF); -#endif - } else { AscSetChipLramAddr(iop_base, addr); word_data = AscGetChipLramData(iop_base); - -#if CC_LITTLE_ENDIAN_HOST byte_data = (uchar) (word_data & 0xFF); -#else - byte_data = (uchar) ((word_data >> 8) & 0xFF); -#endif - } return (byte_data); } @@ -8861,7 +9699,6 @@ ) { ushort word_data; - AscSetChipLramAddr(iop_base, addr); word_data = AscGetChipLramData(iop_base); return (word_data); @@ -8875,18 +9712,9 @@ { ushort val_low, val_high; ulong dword_data; - AscSetChipLramAddr(iop_base, addr); - -#if CC_LITTLE_ENDIAN_HOST val_low = AscGetChipLramData(iop_base); - - val_high = AscGetChipLramData(iop_base); -#else val_high = AscGetChipLramData(iop_base); - val_low = AscGetChipLramData(iop_base); -#endif - dword_data = ((ulong) val_high << 16) | (ulong) val_low; return (dword_data); } @@ -8899,7 +9727,7 @@ ) { AscSetChipLramAddr(iop_base, addr); - AscPutChipLramData(iop_base, word_val); + AscSetChipLramData(iop_base, word_val); return; } @@ -8911,20 +9739,11 @@ ) { ushort word_val; - AscSetChipLramAddr(iop_base, addr); - -#if CC_LITTLE_ENDIAN_HOST word_val = (ushort) dword_val; - AscPutChipLramData(iop_base, word_val); - word_val = (ushort) (dword_val >> 16); - AscPutChipLramData(iop_base, word_val); -#else + AscSetChipLramData(iop_base, word_val); word_val = (ushort) (dword_val >> 16); - AscPutChipLramData(iop_base, word_val); - word_val = (ushort) dword_val; - AscPutChipLramData(iop_base, word_val); -#endif + AscSetChipLramData(iop_base, word_val); return; } @@ -8936,7 +9755,6 @@ ) { ushort word_data; - if (isodd_word(addr)) { addr--; word_data = AscReadLramWord(iop_base, addr); @@ -8951,24 +9769,8 @@ return; } -int -AscVerWriteLramWord( - PortAddr iop_base, - ushort addr, - ushort word_val -) -{ - int sta; - sta = 0; - AscSetChipLramAddr(iop_base, addr); - AscPutChipLramData(iop_base, word_val); - AscSetChipLramAddr(iop_base, addr); - if (word_val != AscGetChipLramData(iop_base)) { - sta = ERR; - } - return (sta); -} + void AscMemWordCopyToLram( @@ -9018,7 +9820,6 @@ { ulong sum; int i; - sum = 0L; for (i = 0; i < words; i++, s_addr += 2) { sum += AscReadLramWord(iop_base, s_addr); @@ -9035,19 +9836,20 @@ ) { rint i; - AscSetChipLramAddr(iop_base, s_addr); for (i = 0; i < words; i++) { - AscPutChipLramData(iop_base, set_wval); + AscSetChipLramData(iop_base, set_wval); } return; } + int AscScsiInquiry( - ASC_DVC_VAR asc_ptr_type * asc_dvc, - ASC_SCSI_REQ_Q dosfar * scsiq, - uchar dosfar * buf, int buf_len + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_REQ_Q dosfar * scsiq, + uchar dosfar * buf, + int buf_len ) { if (AscScsiSetupCmdQ(asc_dvc, scsiq, buf, @@ -9064,10 +9866,11 @@ return (0); } +#if CC_INIT_TARGET_READ_CAPACITY int AscScsiReadCapacity( - ASC_DVC_VAR asc_ptr_type * asc_dvc, - ASC_SCSI_REQ_Q dosfar * scsiq, + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_REQ_Q dosfar * scsiq, uchar dosfar * info ) { @@ -9087,11 +9890,13 @@ scsiq->r2.cdb_len = 10; return (0); } +#endif +#if CC_INIT_TARGET_TEST_UNIT_READY int AscScsiTestUnitReady( - ASC_DVC_VAR asc_ptr_type * asc_dvc, - ASC_SCSI_REQ_Q dosfar * scsiq + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_REQ_Q dosfar * scsiq ) { if (AscScsiSetupCmdQ(asc_dvc, scsiq, FNULLPTR, @@ -9108,11 +9913,13 @@ scsiq->r2.cdb_len = 6; return (0); } +#endif +#if CC_INIT_TARGET_START_UNIT int AscScsiStartStopUnit( - ASC_DVC_VAR asc_ptr_type * asc_dvc, - ASC_SCSI_REQ_Q dosfar * scsiq, + REG ASC_DVC_VAR asc_ptr_type * asc_dvc, + REG ASC_SCSI_REQ_Q dosfar * scsiq, uchar op_mode ) { @@ -9125,8 +9932,8 @@ scsiq->cdb[2] = 0; scsiq->cdb[3] = 0; scsiq->cdb[4] = op_mode; - scsiq->cdb[5] = 0; scsiq->r2.cdb_len = 6; return (0); } +#endif diff -ur --new-file old/linux/drivers/scsi/advansys.h new/linux/drivers/scsi/advansys.h --- old/linux/drivers/scsi/advansys.h Wed Jan 17 06:27:36 1996 +++ new/linux/drivers/scsi/advansys.h Wed Aug 14 08:59:04 1996 @@ -1,13 +1,16 @@ -/* $Id: advansys.h,v 1.10 1996/01/15 04:51:06 bobf Exp bobf $ */ +/* $Id: advansys.h,v 1.11 1996/08/12 17:20:44 bobf Exp bobf $ */ /* * advansys.h - Linux Host Driver for AdvanSys SCSI Adapters * * Copyright (c) 1995-1996 Advanced System Products, Inc. * - * This driver may be modified and freely distributed provided that - * the above copyright message and this comment are included in the - * distribution. The latest version of this driver is available at - * the AdvanSys FTP and BBS sites listed below. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that redistributions of source + * code retain the above copyright notice and this comment without + * modification. + * + * The latest version of this driver is available at the AdvanSys + * FTP and BBS sites listed below. * * Please send questions, comments, and bug reports to: * bobf@advansys.com (Bob Frey) @@ -16,17 +19,12 @@ #ifndef _ADVANSYS_H #define _ADVANSYS_H -/* The driver can be used in Linux 1.2.X or 1.3.X. */ -#if !defined(LINUX_1_2) && !defined(LINUX_1_3) +/* Convert Linux Version, Patch-level, Sub-level to LINUX_VERSION_CODE. */ +#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S)) + #ifndef LINUX_VERSION_CODE #include #endif /* LINUX_VERSION_CODE */ -#if LINUX_VERSION_CODE > 65536 + 3 * 256 -#define LINUX_1_3 -#else /* LINUX_VERSION_CODE */ -#define LINUX_1_2 -#endif /* LINUX_VERSION_CODE */ -#endif /* !defined(LINUX_1_2) && !defined(LINUX_1_3) */ /* * Scsi_Host_Template function prototypes. @@ -37,14 +35,18 @@ int advansys_command(Scsi_Cmnd *); int advansys_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); int advansys_abort(Scsi_Cmnd *); +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89) int advansys_reset(Scsi_Cmnd *); -#ifdef LINUX_1_2 +#else /* version >= v1.3.89 */ +int advansys_reset(Scsi_Cmnd *, unsigned int); +#endif /* version >= v1.3.89 */ +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) int advansys_biosparam(Disk *, int, int[]); -#else /* LINUX_1_3 */ +#else /* version >= v1.3.0 */ int advansys_biosparam(Disk *, kdev_t, int[]); extern struct proc_dir_entry proc_scsi_advansys; int advansys_proc_info(char *, char **, off_t, int, int, int); -#endif /* LINUX_1_3 */ +#endif /* version >= v1.3.0 */ /* init/main.c setup function */ void advansys_setup(char *, int *); @@ -52,7 +54,7 @@ /* * AdvanSys Host Driver Scsi_Host_Template (struct SHT) from hosts.h. */ -#ifdef LINUX_1_2 +#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0) #define ADVANSYS { \ NULL, /* struct SHT *next */ \ NULL, /* int *usage_count */ \ @@ -88,7 +90,7 @@ */ \ DISABLE_CLUSTERING, /* unsigned use_clustering:1 */ \ } -#else /* LINUX_1_3 */ +#else /* version >= v1.3.0 */ #define ADVANSYS { \ NULL, /* struct SHT *next */ \ NULL, /* long *usage_count */ \ @@ -103,7 +105,9 @@ advansys_queuecommand, \ /* int (*queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ \ advansys_abort, /* int (*abort)(Scsi_Cmnd *) */ \ - advansys_reset, /* int (*reset)(Scsi_Cmnd *) */ \ + advansys_reset, \ + /* version < v1.3.89 int (*reset)(Scsi_Cmnd *) */ \ + /* version >= v1.3.89 int (*reset)(Scsi_Cmnd *, unsigned int) */ \ NULL, /* int (*slave_attach)(int, int) */ \ advansys_biosparam, /* int (* bios_param)(Disk *, kdev_t, int []) */ \ /* \ @@ -127,5 +131,5 @@ */ \ DISABLE_CLUSTERING, /* unsigned use_clustering:1 */ \ } -#endif /* LINUX_1_3 */ +#endif /* version >= v1.3.0 */ #endif /* _ADVANSYS_H */ diff -ur --new-file old/linux/drivers/scsi/aha152x.c new/linux/drivers/scsi/aha152x.c --- old/linux/drivers/scsi/aha152x.c Sun Jun 9 11:47:12 1996 +++ new/linux/drivers/scsi/aha152x.c Sat Aug 17 20:02:50 1996 @@ -20,9 +20,15 @@ * General Public License for more details. * * - * $Id: aha152x.c,v 1.16 1996/06/09 00:04:56 root Exp $ + * $Id: aha152x.c,v 1.17 1996/08/17 16:05:14 fischer Exp fischer $ * * $Log: aha152x.c,v $ + * Revision 1.17 1996/08/17 16:05:14 fischer + * - biosparam improved + * - interrupt verification + * - updated documentation + * - cleanups + * * Revision 1.16 1996/06/09 00:04:56 root * - added configuration symbols for insmod (aha152x/aha152x1) * @@ -39,7 +45,7 @@ * (to avoid spurious interrupts) * * Revision 1.12 1995/12/16 12:26:07 fischer - * - barrier()'s added + * - barrier()s added * - configurable RESET delay added * * Revision 1.11 1995/12/06 21:18:35 fischer @@ -177,34 +183,115 @@ DESCRIPTION: - This is the Linux low-level SCSI driver for Adaptec AHA-1520/1522 - SCSI host adapters. + This is the Linux low-level SCSI driver for Adaptec AHA-1520/1522 SCSI + host adapters. + + CONFIGURATION ARGUMENTS: - PER-DEFINE CONFIGURABLE OPTIONS: + IOPORT base io address (0x340/0x140) + IRQ interrupt level (9-12; default 11) + SCSI_ID scsi id of controller (0-7; default 7) + RECONNECT allow targets to disconnect from the bus (0/1; default 1 [on]) + PARITY enable parity checking (0/1; default 1 [on]) + SYNCHRONOUS enable synchronous transfers (0/1; default 0 [off]) + (NOT WORKING YET) + DELAY: bus reset delay (default 100) + EXT_TRANS: enable extended translation (0/1: default 0 [off]) + (see NOTES below) - AUTOCONF: - use configuration the controller reports (only 152x) + COMPILE TIME CONFIGURATION (put into AHA152X in drivers/scsi/Makefile): - SKIP_BIOSTEST: + -DAUTOCONF + use configuration the controller reports (AHA-152x only) + + -DSKIP_BIOSTEST Don't test for BIOS signature (AHA-1510 or disabled BIOS) - SETUP0 { IOPORT, IRQ, SCSI_ID, RECONNECT, PARITY, SYNCHRONOUS, DELAY }: - override for the first controller + -DSETUP0="{ IOPORT, IRQ, SCSI_ID, RECONNECT, PARITY, SYNCHRONOUS, DELAY, EXT_TRANS }" + override for the first controller - SETUP1 { IOPORT, IRQ, SCSI_ID, RECONNECT, PARITY, SYNCHRONOUS, DELAY }: + -DSETUP1="{ IOPORT, IRQ, SCSI_ID, RECONNECT, PARITY, SYNCHRONOUS, DELAY, EXT_TRANS }" override for the second controller LILO COMMAND LINE OPTIONS: - aha152x=[,[,[,[,[,[,]]]]]] + aha152x=[,[,[,[,[,[, [,1GB: + - take current geometry from the partition table + (using scsicam_bios_param and accept only `valid' geometries, + ie. either (C/32/64) or (C/63/255)). This can be extended + translation even if it's not enabled in the driver. + - if that fails, take extended translation if enabled by override, + kernel or module parameter, otherwise take default translation and + ask the user for verification. This might on not yet partitioned + disks or REFERENCES USED: @@ -257,6 +344,8 @@ #include "aha152x.h" #include +#include + struct proc_dir_entry proc_scsi_aha152x = { PROC_SCSI_AHA152X, 7, "aha152x", S_IFDIR | S_IRUGO | S_IXUGO, 2 @@ -338,11 +427,11 @@ #if defined(MODULE) #if defined(DEBUG_AHA152X) -int aha152x[] = { 0, 11, 7, 1, 1, 0, DELAY_DEFAULT, DEBUG_DEFAULT }; -int aha152x1[] = { 0, 11, 7, 1, 1, 0, DELAY_DEFAULT, DEBUG_DEFAULT }; +int aha152x[] = { 0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0, DEBUG_DEFAULT }; +int aha152x1[] = { 0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0, DEBUG_DEFAULT }; #else -int aha152x[] = { 0, 11, 7, 1, 1, 0, DELAY_DEFAULT }; -int aha152x1[] = { 0, 11, 7, 1, 1, 0, DELAY_DEFAULT }; +int aha152x[] = { 0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0 }; +int aha152x1[] = { 0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0 }; #endif #endif @@ -356,6 +445,7 @@ int parity; int synchronous; int delay; + int ext_trans; #ifdef DEBUG_AHA152X int debug; #endif @@ -365,14 +455,15 @@ static struct Scsi_Host *aha152x_host[IRQS]; #define HOSTDATA(shpnt) ((struct aha152x_hostdata *) &shpnt->hostdata) -#define CURRENT_SC (HOSTDATA(shpnt)->current_SC) -#define ISSUE_SC (HOSTDATA(shpnt)->issue_SC) -#define DISCONNECTED_SC (HOSTDATA(shpnt)->disconnected_SC) +#define CURRENT_SC (HOSTDATA(shpnt)->current_SC) +#define ISSUE_SC (HOSTDATA(shpnt)->issue_SC) +#define DISCONNECTED_SC (HOSTDATA(shpnt)->disconnected_SC) #define DELAY (HOSTDATA(shpnt)->delay) -#define SYNCRATE (HOSTDATA(shpnt)->syncrate[CURRENT_SC->target]) +#define EXT_TRANS (HOSTDATA(shpnt)->ext_trans) +#define SYNCRATE (HOSTDATA(shpnt)->syncrate[CURRENT_SC->target]) #define MSG(i) (HOSTDATA(shpnt)->message[i]) #define MSGLEN (HOSTDATA(shpnt)->message_len) -#define ADDMSG(x) (MSG(MSGLEN++)=x) +#define ADDMSG(x) (MSG(MSGLEN++)=x) struct aha152x_hostdata { Scsi_Cmnd *issue_SC; @@ -387,6 +478,9 @@ int parity; int synchronous; int delay; + int ext_trans; + + int swint; unsigned char syncrate[8]; @@ -441,12 +535,12 @@ #define ADDRESS_COUNT (sizeof(addresses) / sizeof(void *)) /* signatures for various AIC-6[23]60 based controllers. - The point in detecting signatures is to avoid useless - and maybe harmful probes on ports. I'm not sure that - all listed boards pass auto-configuration. For those - which fail the BIOS signature is obsolete, because - user intervention to supply the configuration is - needed anyway. */ + The point in detecting signatures is to avoid useless and maybe + harmful probes on ports. I'm not sure that all listed boards pass + auto-configuration. For those which fail the BIOS signature is + obsolete, because user intervention to supply the configuration is + needed anyway. May be an information whether or not the BIOS supports + extended translation could be also useful here. */ static struct signature { char *signature; int sig_offset; @@ -473,7 +567,7 @@ unsigned long the_time = jiffies + amount; /* 0.01 seconds per jiffy */ while (jiffies < the_time) - barrier(); + barrier(); } /* @@ -486,12 +580,11 @@ new_SC->host_scribble = (unsigned char *) NULL; if(!*SC) *SC=new_SC; - else - { - for(end=*SC; end->host_scribble; end = (Scsi_Cmnd *) end->host_scribble) - ; - end->host_scribble = (unsigned char *) new_SC; - } + else { + for(end=*SC; end->host_scribble; end = (Scsi_Cmnd *) end->host_scribble) + ; + end->host_scribble = (unsigned char *) new_SC; + } } static inline Scsi_Cmnd *remove_first_SC(Scsi_Cmnd **SC) @@ -518,6 +611,7 @@ prev->host_scribble = ptr->host_scribble; else *SC= (Scsi_Cmnd *) ptr->host_scribble; + return ptr; } @@ -548,36 +642,30 @@ { int phase, sstat1; - while(1) - { - do - { - while(!((sstat1 = GETPORT(SSTAT1)) & (BUSFREE|SCSIRSTI|REQINIT))) - barrier(); - if(sstat1 & BUSFREE) - return P_BUSFREE; - if(sstat1 & SCSIRSTI) - { - printk("aha152x: RESET IN\n"); - SETPORT(SSTAT1, SCSIRSTI); - } - } - while(TESTHI(SCSISIG, ACKI) || TESTLO(SSTAT1, REQINIT)); - - SETPORT(SSTAT1, CLRSCSIPERR); - - phase = GETPORT(SCSISIG) & P_MASK ; - - if(TESTHI(SSTAT1, SCSIPERR)) - { - if((phase & (CDO|MSGO))==0) /* DATA phase */ - return P_PARITY; + while(1) { + do { + while(!((sstat1 = GETPORT(SSTAT1)) & (BUSFREE|SCSIRSTI|REQINIT))) + barrier(); + if(sstat1 & BUSFREE) + return P_BUSFREE; + if(sstat1 & SCSIRSTI) { + printk("aha152x: RESET IN\n"); + SETPORT(SSTAT1, SCSIRSTI); + } + } while(TESTHI(SCSISIG, ACKI) || TESTLO(SSTAT1, REQINIT)); - make_acklow(shpnt); - } - else - return phase; - } + SETPORT(SSTAT1, CLRSCSIPERR); + + phase = GETPORT(SCSISIG) & P_MASK ; + + if(TESTHI(SSTAT1, SCSIPERR)) { + if((phase & (CDO|MSGO))==0) /* DATA phase */ + return P_PARITY; + + make_acklow(shpnt); + } else + return phase; + } } /* called from init/main.c */ @@ -594,25 +682,23 @@ setup[setup_count].parity = ints[0] >= 5 ? ints[5] : 1; setup[setup_count].synchronous = ints[0] >= 6 ? ints[6] : 0 /* FIXME: 1 */; setup[setup_count].delay = ints[0] >= 7 ? ints[7] : DELAY_DEFAULT; + setup[setup_count].ext_trans = ints[0] >= 8 ? ints[8] : 0; #ifdef DEBUG_AHA152X - setup[setup_count].debug = ints[0] >= 8 ? ints[8] : DEBUG_DEFAULT; - if(ints[0]>8) - { - printk("aha152x: usage: aha152x=[,[," - "[,[,[,[,[,]]]]]]]\n"); + setup[setup_count].debug = ints[0] >= 9 ? ints[9] : DEBUG_DEFAULT; + if(ints[0]>9) { + printk("aha152x: usage: aha152x=[,[," + "[,[,[,[,[,[,]]]]]]]]\n"); #else - if(ints[0]>7) - { - printk("aha152x: usage: aha152x=[,[," - "[,[,[,[,]]]]]]\n"); + if(ints[0]>8) { + printk("aha152x: usage: aha152x=[,[," + "[,[,[,[,[,]]]]]]]\n"); #endif - } - else + } else setup_count++; } /* - Test, if port_base is valid. + * Test, if port_base is valid. */ static int aha152x_porttest(int io_port) { @@ -647,7 +733,7 @@ if(!aha152x_porttest(setup->io_port)) return 0; - if((setup->irq < IRQ_MIN) && (setup->irq > IRQ_MAX)) + if(setup->irqirq>IRQ_MAX) return 0; if((setup->scsiid < 0) || (setup->scsiid > 7)) @@ -661,10 +747,24 @@ if((setup->synchronous < 0) || (setup->synchronous > 1)) return 0; + + if((setup->ext_trans < 0) || (setup->ext_trans > 1)) + return 0; + return 1; } +void aha152x_swintr(int irqno, void *dev_id, struct pt_regs * regs) +{ + struct Scsi_Host *shpnt = aha152x_host[irqno-IRQ_MIN]; + + if(!shpnt) + panic("aha152x: catched software interrupt for unknown controller.\n"); + + HOSTDATA(shpnt)->swint++; +} + int aha152x_detect(Scsi_Host_Template * tpnt) { @@ -678,56 +778,56 @@ for(i=0; iio_port = setup[i].io_port; - shpnt->n_io_port = IO_RANGE; - shpnt->irq = setup[i].irq; - - ISSUE_SC = (Scsi_Cmnd *) NULL; - CURRENT_SC = (Scsi_Cmnd *) NULL; - DISCONNECTED_SC = (Scsi_Cmnd *) NULL; - - HOSTDATA(shpnt)->reconnect = setup[i].reconnect; - HOSTDATA(shpnt)->parity = setup[i].parity; - HOSTDATA(shpnt)->synchronous = setup[i].synchronous; - HOSTDATA(shpnt)->delay = setup[i].delay; + for(i=0; iio_port = setup[i].io_port; + shpnt->n_io_port = IO_RANGE; + shpnt->irq = setup[i].irq; + + ISSUE_SC = (Scsi_Cmnd *) NULL; + CURRENT_SC = (Scsi_Cmnd *) NULL; + DISCONNECTED_SC = (Scsi_Cmnd *) NULL; + + HOSTDATA(shpnt)->reconnect = setup[i].reconnect; + HOSTDATA(shpnt)->parity = setup[i].parity; + HOSTDATA(shpnt)->synchronous = setup[i].synchronous; + HOSTDATA(shpnt)->delay = setup[i].delay; + HOSTDATA(shpnt)->ext_trans = setup[i].ext_trans; #ifdef DEBUG_AHA152X - HOSTDATA(shpnt)->debug = setup[i].debug; + HOSTDATA(shpnt)->debug = setup[i].debug; #endif - HOSTDATA(shpnt)->aborting = 0; - HOSTDATA(shpnt)->abortion_complete = 0; - HOSTDATA(shpnt)->abort_result = 0; - HOSTDATA(shpnt)->commands = 0; + HOSTDATA(shpnt)->aborting = 0; + HOSTDATA(shpnt)->abortion_complete = 0; + HOSTDATA(shpnt)->abort_result = 0; + HOSTDATA(shpnt)->commands = 0; - HOSTDATA(shpnt)->message_len = 0; + HOSTDATA(shpnt)->message_len = 0; - for(j=0; j<8; j++) - HOSTDATA(shpnt)->syncrate[j] = 0; + for(j=0; j<8; j++) + HOSTDATA(shpnt)->syncrate[j] = 0; - SETPORT(SCSIID, setup[i].scsiid << 4); - shpnt->this_id=setup[i].scsiid; + SETPORT(SCSIID, setup[i].scsiid << 4); + shpnt->this_id=setup[i].scsiid; - if(setup[i].reconnect) - shpnt->hostt->can_queue=AHA152X_MAXQUEUE; + if(setup[i].reconnect) + shpnt->hostt->can_queue=AHA152X_MAXQUEUE; - /* RESET OUT */ - SETBITS(SCSISEQ, SCSIRSTO); - do_pause(30); - CLRBITS(SCSISEQ, SCSIRSTO); - do_pause(setup[i].delay); + /* RESET OUT */ + SETBITS(SCSISEQ, SCSIRSTO); + do_pause(30); + CLRBITS(SCSISEQ, SCSIRSTO); + do_pause(setup[i].delay); - aha152x_reset_ports(shpnt); + aha152x_reset_ports(shpnt); - printk("aha152x%d: vital data: PORTBASE=0x%03x, IRQ=%d, SCSI ID=%d," - " reconnect=%s, parity=%s, synchronous=%s, delay=%d\n", - i, - shpnt->io_port, - shpnt->irq, - shpnt->this_id, - HOSTDATA(shpnt)->reconnect ? "enabled" : "disabled", - HOSTDATA(shpnt)->parity ? "enabled" : "disabled", - HOSTDATA(shpnt)->synchronous ? "enabled" : "disabled", - HOSTDATA(shpnt)->delay); + printk("aha152x%d: vital data: PORTBASE=0x%03x, IRQ=%d, SCSI ID=%d," + " reconnect=%s, parity=%s, synchronous=%s, delay=%d, extended translation=%s\n", + i, + shpnt->io_port, + shpnt->irq, + shpnt->this_id, + HOSTDATA(shpnt)->reconnect ? "enabled" : "disabled", + HOSTDATA(shpnt)->parity ? "enabled" : "disabled", + HOSTDATA(shpnt)->synchronous ? "enabled" : "disabled", + HOSTDATA(shpnt)->delay, + HOSTDATA(shpnt)->ext_trans ? "enabled" : "disabled"); + + request_region(shpnt->io_port, IO_RANGE, "aha152x"); /* Register */ + + /* not expecting any interrupts */ + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, 0); + + SETBITS(DMACNTRL0, INTEN); + + ok = request_irq(shpnt->irq, aha152x_swintr, SA_INTERRUPT, "aha152x", NULL); + if(ok<0) { + if(ok == -EINVAL) + printk("aha152x%d: bad IRQ %d.\n", i, shpnt->irq); + else if(ok == -EBUSY) + printk("aha152x%d: IRQ %d already in use.\n", i, shpnt->irq); + else + printk("\naha152x%d: Unexpected error code %d on requesting IRQ %d.\n", i, ok, shpnt->irq); + printk("aha152x: driver needs an IRQ.\n"); - request_region(shpnt->io_port, IO_RANGE, "aha152x"); /* Register */ - - /* not expecting any interrupts */ - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, 0); + scsi_unregister(shpnt); + shpnt=aha152x_host[shpnt->irq-IRQ_MIN]=0; + continue; + } - SETBITS(DMACNTRL0, INTEN); + HOSTDATA(shpnt)->swint=0; - ok = request_irq(setup[i].irq, aha152x_intr, SA_INTERRUPT, "aha152x", NULL); - - if(ok<0) - { - if(ok == -EINVAL) - { - printk("aha152x%d: bad IRQ %d.\n", i, setup[i].irq); - printk(" Contact author.\n"); - } - else - if(ok == -EBUSY) - printk("aha152x%d: IRQ %d already in use. Configure another.\n", - i, setup[i].irq); - else - { - printk("\naha152x%d: Unexpected error code on" - " requesting IRQ %d.\n", i, setup[i].irq); - printk(" Contact author.\n"); - } - printk("aha152x: driver needs an IRQ.\n"); - continue; - } + printk("aha152x: trying software interrupt, "); + SETBITS(DMACNTRL0, SWINT); + + the_time=jiffies+100; + while(!HOSTDATA(shpnt)->swint && jiffiesirq,0); + + if(!HOSTDATA(shpnt)->swint) { + if(TESTHI(DMASTAT, INTSTAT)) { + printk("lost.\n"); + } else { + printk("failed.\n"); + } + + printk("aha152x: IRQ %d possibly wrong. Please verify.\n", shpnt->irq); + + scsi_unregister(shpnt); + shpnt=aha152x_host[shpnt->irq-IRQ_MIN]=0; + continue; } + + printk("ok.\n"); + + CLRBITS(DMACNTRL0, SWINT); + + /* clear interrupts */ + SETPORT(SSTAT0, 0x7f); + SETPORT(SSTAT1, 0xef); + + if(request_irq(shpnt->irq,aha152x_intr,SA_INTERRUPT,"aha152x",NULL)<0) { + printk("aha152x: failed to reassign interrupt.\n"); + } + } return (setup_count>0); } @@ -943,14 +1079,13 @@ #endif #if defined(DEBUG_QUEUE) - if(HOSTDATA(shpnt)->debug & debug_queue) - { - printk("SCpnt (target = %d lun = %d cmnd = ", - SCpnt->target, SCpnt->lun); + if(HOSTDATA(shpnt)->debug & debug_queue) { + printk("SCpnt (target = %d lun = %d cmnd = ", + SCpnt->target, SCpnt->lun); print_command(SCpnt->cmnd); - printk(", cmd_len=%d, pieces = %d size = %u), ", - SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen); - disp_ports(shpnt); + printk(", cmd_len=%d, pieces = %d size = %u), ", + SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen); + disp_ports(shpnt); } #endif @@ -963,22 +1098,18 @@ SCp.buffers_residual : left buffers in list SCp.phase : current state of the command */ SCpnt->SCp.phase = not_issued; - if (SCpnt->use_sg) - { - SCpnt->SCp.buffer = - (struct scatterlist *) SCpnt->request_buffer; - SCpnt->SCp.ptr = SCpnt->SCp.buffer->address; - SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; - SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1; - } - else - { - SCpnt->SCp.ptr = (char *)SCpnt->request_buffer; - SCpnt->SCp.this_residual = SCpnt->request_bufflen; - SCpnt->SCp.buffer = NULL; - SCpnt->SCp.buffers_residual = 0; - } - + if (SCpnt->use_sg) { + SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->request_buffer; + SCpnt->SCp.ptr = SCpnt->SCp.buffer->address; + SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; + SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1; + } else { + SCpnt->SCp.ptr = (char *)SCpnt->request_buffer; + SCpnt->SCp.this_residual = SCpnt->request_bufflen; + SCpnt->SCp.buffer = NULL; + SCpnt->SCp.buffers_residual = 0; + } + SCpnt->SCp.Status = CHECK_CONDITION; SCpnt->SCp.Message = 0; SCpnt->SCp.have_data_in = 0; @@ -998,11 +1129,10 @@ append_SC(&ISSUE_SC, SCpnt); /* Enable bus free interrupt, when we aren't currently on the bus */ - if(!CURRENT_SC) - { - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); - } + if(!CURRENT_SC) { + SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); + SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); + } restore_flags(flags); #if defined(DEBUG_RACE) @@ -1035,10 +1165,9 @@ cli(); #if defined(DEBUG_ABORT) - if(HOSTDATA(shpnt)->debug & debug_abort) - { - printk("aha152x: abort(), SCpnt=0x%08x, ", (unsigned int) SCpnt); - show_queues(shpnt); + if(HOSTDATA(shpnt)->debug & debug_abort) { + printk("aha152x: abort(), SCpnt=0x%08x, ", (unsigned int) SCpnt); + show_queues(shpnt); } #endif @@ -1048,43 +1177,48 @@ prev=ptr, ptr=(Scsi_Cmnd *) ptr->host_scribble) ; - if(ptr) - { - /* dequeue */ - if(prev) - prev->host_scribble = ptr->host_scribble; - else - ISSUE_SC = (Scsi_Cmnd *) ptr->host_scribble; - restore_flags(flags); + if(ptr) { + /* dequeue */ + if(prev) + prev->host_scribble = ptr->host_scribble; + else + ISSUE_SC = (Scsi_Cmnd *) ptr->host_scribble; - ptr->host_scribble = NULL; - ptr->result = DID_ABORT << 16; - ptr->scsi_done(ptr); - return SCSI_ABORT_SUCCESS; - } + HOSTDATA(shpnt)->commands--; + + restore_flags(flags); + + ptr->host_scribble = NULL; + ptr->result = DID_ABORT << 16; + ptr->scsi_done(ptr); + + return SCSI_ABORT_SUCCESS; + } /* if the bus is busy or a command is currently processed, we can't do anything more */ - if (TESTLO(SSTAT1, BUSFREE) || (CURRENT_SC && CURRENT_SC!=SCpnt)) - { - /* fail abortion, if bus is busy */ + if (TESTLO(SSTAT1, BUSFREE) || (CURRENT_SC && CURRENT_SC!=SCpnt)) { + /* fail abortion, if bus is busy */ - if(!CURRENT_SC) - printk("bus busy w/o current command, "); + if(!CURRENT_SC) + printk("bus busy w/o current command, "); - restore_flags(flags); - return SCSI_ABORT_BUSY; - } + restore_flags(flags); + + return SCSI_ABORT_BUSY; + } /* bus is free */ - if(CURRENT_SC) - { + if(CURRENT_SC) { + HOSTDATA(shpnt)->commands--; + /* target entered bus free before COMMAND COMPLETE, nothing to abort */ restore_flags(flags); - CURRENT_SC->result = DID_ERROR << 16; - CURRENT_SC->scsi_done(CURRENT_SC); - CURRENT_SC = (Scsi_Cmnd *) NULL; + CURRENT_SC->result = DID_ERROR << 16; + CURRENT_SC->scsi_done(CURRENT_SC); + CURRENT_SC = (Scsi_Cmnd *) NULL; + return SCSI_ABORT_SUCCESS; } @@ -1094,54 +1228,57 @@ prev=ptr, ptr=(Scsi_Cmnd *) ptr->host_scribble) ; - if(ptr) - if(!HOSTDATA(shpnt)->aborting) - { - /* dequeue */ - if(prev) - prev->host_scribble = ptr->host_scribble; - else - DISCONNECTED_SC = (Scsi_Cmnd *) ptr->host_scribble; - - /* set command current and initiate selection, - let the interrupt routine take care of the abortion */ - CURRENT_SC = ptr; - ptr->SCp.phase = in_selection|aborted; - SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target); - - ADDMSG(ABORT); - - /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */ - SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0)); - SETPORT(SIMODE1, ENSELTIMO); - - /* Enable SELECTION OUT sequence */ - SETBITS(SCSISEQ, ENSELO | ENAUTOATNO); - - SETBITS(DMACNTRL0, INTEN); - HOSTDATA(shpnt)->abort_result=SCSI_ABORT_SUCCESS; - HOSTDATA(shpnt)->aborting++; - HOSTDATA(shpnt)->abortion_complete=0; + if(!ptr) { + /* command wasn't found */ + printk("command not found\n"); + restore_flags(flags); - sti(); /* Hi Eric, guess what ;-) */ - - /* sleep until the abortion is complete */ - while(!HOSTDATA(shpnt)->abortion_complete) - barrier(); - HOSTDATA(shpnt)->aborting=0; - return HOSTDATA(shpnt)->abort_result; - } + return SCSI_ABORT_NOT_RUNNING; + } + + if(!HOSTDATA(shpnt)->aborting) { + /* dequeue */ + if(prev) + prev->host_scribble = ptr->host_scribble; else - { - /* we're already aborting a command */ - restore_flags(flags); - return SCSI_ABORT_BUSY; - } + DISCONNECTED_SC = (Scsi_Cmnd *) ptr->host_scribble; - /* command wasn't found */ - printk("command not found\n"); - restore_flags(flags); - return SCSI_ABORT_NOT_RUNNING; + HOSTDATA(shpnt)->commands--; + + /* set command current and initiate selection, + let the interrupt routine take care of the abortion */ + CURRENT_SC = ptr; + ptr->SCp.phase = in_selection|aborted; + SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target); + + ADDMSG(ABORT); + + /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */ + SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0)); + SETPORT(SIMODE1, ENSELTIMO); + + /* Enable SELECTION OUT sequence */ + SETBITS(SCSISEQ, ENSELO | ENAUTOATNO); + + SETBITS(DMACNTRL0, INTEN); + HOSTDATA(shpnt)->abort_result=SCSI_ABORT_SUCCESS; + HOSTDATA(shpnt)->aborting++; + HOSTDATA(shpnt)->abortion_complete=0; + + sti(); /* Hi Eric, guess what ;-) */ + + /* sleep until the abortion is complete */ + while(!HOSTDATA(shpnt)->abortion_complete) + barrier(); + HOSTDATA(shpnt)->aborting=0; + + return HOSTDATA(shpnt)->abort_result; + } else { + /* we're already aborting a command */ + restore_flags(flags); + + return SCSI_ABORT_BUSY; + } } /* @@ -1182,7 +1319,7 @@ * Reset registers, reset a hanging bus and * kill active and disconnected commands for target w/o soft reset */ -int aha152x_reset(Scsi_Cmnd *SCpnt) +int aha152x_reset(Scsi_Cmnd *SCpnt, unsigned int unused) { struct Scsi_Host *shpnt = SCpnt->host; unsigned long flags; @@ -1191,74 +1328,66 @@ aha152x_reset_ports(shpnt); /* Reset, if bus hangs */ - if(TESTLO(SSTAT1, BUSFREE)) - { - CLRBITS(DMACNTRL0, INTEN); + if(TESTLO(SSTAT1, BUSFREE)) { + CLRBITS(DMACNTRL0, INTEN); #if defined(DEBUG_RESET) - if(HOSTDATA(shpnt)->debug & debug_reset) - { - printk("aha152x: reset(), bus not free: SCSI RESET OUT\n"); - show_queues(shpnt); - } + if(HOSTDATA(shpnt)->debug & debug_reset) { + printk("aha152x: reset(), bus not free: SCSI RESET OUT\n"); + show_queues(shpnt); + } #endif - ptr=CURRENT_SC; - if(ptr && !ptr->device->soft_reset) - { - ptr->host_scribble = NULL; - ptr->result = DID_RESET << 16; - ptr->scsi_done(CURRENT_SC); - CURRENT_SC=NULL; - } - - save_flags(flags); - cli(); - prev=NULL; ptr=DISCONNECTED_SC; - while(ptr) - { - if(!ptr->device->soft_reset) - { - if(prev) - prev->host_scribble = ptr->host_scribble; - else - DISCONNECTED_SC = (Scsi_Cmnd *) ptr->host_scribble; - - next = (Scsi_Cmnd *) ptr->host_scribble; - - ptr->host_scribble = NULL; - ptr->result = DID_RESET << 16; - ptr->scsi_done(ptr); - - ptr = next; - } - else - { - prev=ptr; - ptr = (Scsi_Cmnd *) ptr->host_scribble; - } - } - restore_flags(flags); + ptr=CURRENT_SC; + if(ptr && !ptr->device->soft_reset) { + ptr->host_scribble = NULL; + ptr->result = DID_RESET << 16; + ptr->scsi_done(CURRENT_SC); + CURRENT_SC=NULL; + } + + save_flags(flags); + cli(); + prev=NULL; ptr=DISCONNECTED_SC; + while(ptr) { + if(!ptr->device->soft_reset) { + if(prev) + prev->host_scribble = ptr->host_scribble; + else + DISCONNECTED_SC = (Scsi_Cmnd *) ptr->host_scribble; -#if defined(DEBUG_RESET) - if(HOSTDATA(shpnt)->debug & debug_reset) - { - printk("commands on targets w/ soft-resets:\n"); - show_queues(shpnt); - } -#endif - - /* RESET OUT */ - SETPORT(SCSISEQ, SCSIRSTO); - do_pause(30); - SETPORT(SCSISEQ, 0); - do_pause(DELAY); + next = (Scsi_Cmnd *) ptr->host_scribble; - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); + ptr->host_scribble = NULL; + ptr->result = DID_RESET << 16; + ptr->scsi_done(ptr); + + ptr = next; + } else { + prev=ptr; + ptr = (Scsi_Cmnd *) ptr->host_scribble; + } + } + restore_flags(flags); - SETPORT(DMACNTRL0, INTEN); +#if defined(DEBUG_RESET) + if(HOSTDATA(shpnt)->debug & debug_reset) { + printk("commands on targets w/ soft-resets:\n"); + show_queues(shpnt); } +#endif + + /* RESET OUT */ + SETPORT(SCSISEQ, SCSIRSTO); + do_pause(30); + SETPORT(SCSISEQ, 0); + do_pause(DELAY); + + SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); + SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); + + SETPORT(DMACNTRL0, INTEN); + } return SCSI_RESET_SUCCESS; } @@ -1268,29 +1397,54 @@ */ int aha152x_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array) { + struct Scsi_Host *shpnt=disk->device->host; + #if defined(DEBUG_BIOSPARAM) if(HOSTDATA(shpnt)->debug & debug_biosparam) printk("aha152x_biosparam: dev=%s, size=%d, ", kdevname(dev), disk->capacity); #endif - - if(disk->capacity<=1024*64*32) { - info_array[0]=64; - info_array[1]=32; - info_array[2]=disk->capacity / (64 * 32); - } else { - info_array[0] = 255; - info_array[1] = 63; - info_array[2] = disk->capacity / (255 * 63); - if(info_array[2] > 1023) - info_array[2]=1023; + + /* try default translation */ + info_array[0]=64; + info_array[1]=32; + info_array[2]=disk->capacity / (64 * 32); + + /* for disks >1GB do some guessing */ + if(info_array[2]>=1024) { + int info[3]; + + /* try to figure out the geometry from the partition table */ + if(scsicam_bios_param(disk, dev, info)<0 || + !((info[0]==64 && info[1]==32) || (info[0]==255 && info[1]==63))) { + if(EXT_TRANS) { + printk("aha152x: unable to verify geometry for disk with >1GB.\n" + " using extended translation.\n"); + info_array[0] = 255; + info_array[1] = 63; + info_array[2] = disk->capacity / (255 * 63); + } else { + printk("aha152x: unable to verify geometry for disk with >1GB.\n" + " Using default translation. Please verify yourself.\n" + " Perhaps you need to enable extended translation in the driver.\n" + " See /usr/src/linux/drivers/scsi/aha152x.c for details.\n"); + } + } else { + info_array[0]=info[0]; + info_array[1]=info[1]; + info_array[2]=info[2]; + + if(info[0]==255 && !EXT_TRANS) { + printk("aha152x: current partition table is using extended translation.\n" + " using it also, although it's not explicty enabled.\n"); + } + } } #if defined(DEBUG_BIOSPARAM) - if(HOSTDATA(shpnt)->debug & debug_biosparam) - { + if(HOSTDATA(shpnt)->debug & debug_biosparam) { printk("bios geometry: head=%d, sec=%d, cyl=%d\n", - info_array[0], info_array[1], info_array[2]); + info_array[0], info_array[1], info_array[2]); printk("WARNING: check, if the bios geometry is correct.\n"); } #endif @@ -1307,68 +1461,66 @@ Scsi_Cmnd *done_SC; #if defined(DEBUG_DONE) - if(HOSTDATA(shpnt)->debug & debug_done) - { + if(HOSTDATA(shpnt)->debug & debug_done) { printk("\naha152x: done(), "); disp_ports(shpnt); } #endif - if (CURRENT_SC) - { + if(CURRENT_SC) { #if defined(DEBUG_DONE) - if(HOSTDATA(shpnt)->debug & debug_done) - printk("done(%x), ", error); + if(HOSTDATA(shpnt)->debug & debug_done) + printk("done(%x), ", error); #endif - save_flags(flags); - cli(); + save_flags(flags); + cli(); - done_SC = CURRENT_SC; - CURRENT_SC = NULL; + done_SC = CURRENT_SC; + CURRENT_SC = NULL; - /* turn led off, when no commands are in the driver */ - HOSTDATA(shpnt)->commands--; - if(!HOSTDATA(shpnt)->commands) - SETPORT(PORTA, 0); /* turn led off */ + /* turn led off, when no commands are in the driver */ + HOSTDATA(shpnt)->commands--; + if(!HOSTDATA(shpnt)->commands) + SETPORT(PORTA, 0); /* turn led off */ #if defined(DEBUG_QUEUES) - if(HOSTDATA(shpnt)->debug & debug_queues) - printk("ok (%d), ", HOSTDATA(shpnt)->commands); + if(HOSTDATA(shpnt)->debug & debug_queues) + printk("ok (%d), ", HOSTDATA(shpnt)->commands); #endif - restore_flags(flags); + restore_flags(flags); - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); + SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); + SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); +#if 0 +/* Why poll for the BUS FREE phase, when we have setup the interrupt!? */ #if defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & debug_phases) - printk("BUS FREE loop, "); + if(HOSTDATA(shpnt)->debug & debug_phases) + printk("BUS FREE loop, "); #endif - while(TESTLO(SSTAT1, BUSFREE)) - barrier(); + while(TESTLO(SSTAT1, BUSFREE)) + barrier(); #if defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & debug_phases) - printk("BUS FREE\n"); + if(HOSTDATA(shpnt)->debug & debug_phases) + printk("BUS FREE\n"); +#endif #endif - done_SC->result = error; - if(done_SC->scsi_done) - { + done_SC->result = error; + if(done_SC->scsi_done) { #if defined(DEBUG_DONE) - if(HOSTDATA(shpnt)->debug & debug_done) - printk("calling scsi_done, "); + if(HOSTDATA(shpnt)->debug & debug_done) + printk("calling scsi_done, "); #endif - done_SC->scsi_done(done_SC); + done_SC->scsi_done(done_SC); #if defined(DEBUG_DONE) - if(HOSTDATA(shpnt)->debug & debug_done) - printk("done returned, "); + if(HOSTDATA(shpnt)->debug & debug_done) + printk("done returned, "); #endif - } - else - panic("aha152x: current_SC->scsi_done() == NULL"); - } - else + } else + panic("aha152x: current_SC->scsi_done() == NULL"); + } else aha152x_panic(shpnt, "done() called outside of command"); } @@ -1390,9 +1542,12 @@ #endif #endif - /* no more interrupts from the controller, while we busy. + if(!shpnt) + panic("aha152x: catched interrupt for unknown controller.\n"); + + /* no more interrupts from the controller, while we're busy. INTEN has to be restored, when we're ready to leave - intr(). To avoid race conditions we have to return + intr(). To avoid race conditions, we have to return immediately afterwards. */ CLRBITS(DMACNTRL0, INTEN); sti(); /* Yes, sti() really needs to be here */ @@ -1403,104 +1558,98 @@ */ if(TESTHI(SSTAT0, SELDI) && DISCONNECTED_SC && - (!CURRENT_SC || (CURRENT_SC->SCp.phase & in_selection)) ) - { - int identify_msg, target, i; + (!CURRENT_SC || (CURRENT_SC->SCp.phase & in_selection)) ) { + int identify_msg, target, i; - /* Avoid conflicts when a target reconnects - while we are trying to connect to another. */ - if(CURRENT_SC) - { + /* Avoid conflicts when a target reconnects + while we are trying to connect to another. */ + if(CURRENT_SC) { #if defined(DEBUG_QUEUES) - if(HOSTDATA(shpnt)->debug & debug_queues) - printk("i+, "); + if(HOSTDATA(shpnt)->debug & debug_queues) + printk("i+, "); #endif - save_flags(flags); - cli(); - append_SC(&ISSUE_SC, CURRENT_SC); - CURRENT_SC=NULL; - restore_flags(flags); - } - - /* disable sequences */ - SETPORT(SCSISEQ, 0); - SETPORT(SSTAT0, CLRSELDI); - SETPORT(SSTAT1, CLRBUSFREE); + save_flags(flags); + cli(); + append_SC(&ISSUE_SC, CURRENT_SC); + CURRENT_SC=NULL; + restore_flags(flags); + } + + /* disable sequences */ + SETPORT(SCSISEQ, 0); + SETPORT(SSTAT0, CLRSELDI); + SETPORT(SSTAT1, CLRBUSFREE); #if defined(DEBUG_QUEUES) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_queues|debug_phases)) - printk("reselected, "); + if(HOSTDATA(shpnt)->debug & (debug_queues|debug_phases)) + printk("reselected, "); #endif - i = GETPORT(SELID) & ~(1 << shpnt->this_id); - target=0; - if(i) - for(; (i & 1)==0; target++, i>>=1) - ; - else - aha152x_panic(shpnt, "reconnecting target unknown"); + i = GETPORT(SELID) & ~(1 << shpnt->this_id); + target=0; + + if(i==0) + aha152x_panic(shpnt, "reconnecting target unknown"); + + for(; (i & 1)==0; target++, i>>=1) + ; #if defined(DEBUG_QUEUES) - if(HOSTDATA(shpnt)->debug & debug_queues) - printk("SELID=%02x, target=%d, ", GETPORT(SELID), target); + if(HOSTDATA(shpnt)->debug & debug_queues) + printk("SELID=%02x, target=%d, ", GETPORT(SELID), target); #endif - SETPORT(SCSIID, (shpnt->this_id << OID_) | target); - SETPORT(SCSISEQ, ENRESELI); + SETPORT(SCSIID, (shpnt->this_id << OID_) | target); + SETPORT(SCSISEQ, ENRESELI); - if(TESTLO(SSTAT0, SELDI)) - aha152x_panic(shpnt, "RESELI failed"); + if(TESTLO(SSTAT0, SELDI)) + aha152x_panic(shpnt, "RESELI failed"); - SETPORT(SCSIRATE, HOSTDATA(shpnt)->syncrate[target]&0x7f); + SETPORT(SCSIRATE, HOSTDATA(shpnt)->syncrate[target]&0x7f); - SETPORT(SCSISIG, P_MSGI); + SETPORT(SCSISIG, P_MSGI); - /* Get identify message */ - if((i=getphase(shpnt))!=P_MSGI) - { - printk("target doesn't enter MSGI to identify (phase=%02x)\n", i); - aha152x_panic(shpnt, "unknown lun"); - } - SETPORT(SCSISEQ, 0); + /* Get identify message */ + if((i=getphase(shpnt))!=P_MSGI) { + printk("target doesn't enter MSGI to identify (phase=%02x)\n", i); + aha152x_panic(shpnt, "unknown lun"); + } + SETPORT(SCSISEQ, 0); - SETPORT(SXFRCTL0, CH1); + SETPORT(SXFRCTL0, CH1); - identify_msg = GETPORT(SCSIBUS); + identify_msg = GETPORT(SCSIBUS); - if(!(identify_msg & IDENTIFY_BASE)) - { - printk("target=%d, inbound message (%02x) != IDENTIFY\n", - target, identify_msg); - aha152x_panic(shpnt, "unknown lun"); - } + if(!(identify_msg & IDENTIFY_BASE)) { + printk("target=%d, inbound message (%02x) != IDENTIFY\n", + target, identify_msg); + aha152x_panic(shpnt, "unknown lun"); + } #if defined(DEBUG_QUEUES) - if(HOSTDATA(shpnt)->debug & debug_queues) - printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f); + if(HOSTDATA(shpnt)->debug & debug_queues) + printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f); #endif - save_flags(flags); - cli(); + save_flags(flags); + cli(); #if defined(DEBUG_QUEUES) - if(HOSTDATA(shpnt)->debug & debug_queues) - printk("d-, "); + if(HOSTDATA(shpnt)->debug & debug_queues) + printk("d-, "); #endif - CURRENT_SC = remove_SC(&DISCONNECTED_SC, - target, - identify_msg & 0x3f); - - if(!CURRENT_SC) - { - printk("lun=%d, ", identify_msg & 0x3f); - aha152x_panic(shpnt, "no disconnected command for that lun"); - } + CURRENT_SC = remove_SC(&DISCONNECTED_SC, target, identify_msg & 0x3f); - CURRENT_SC->SCp.phase &= ~disconnected; - restore_flags(flags); + if(!CURRENT_SC) { + printk("lun=%d, ", identify_msg & 0x3f); + aha152x_panic(shpnt, "no disconnected command for that lun"); + } - make_acklow(shpnt); - if(getphase(shpnt)!=P_MSGI) { + CURRENT_SC->SCp.phase &= ~disconnected; + restore_flags(flags); + + make_acklow(shpnt); + if(getphase(shpnt)!=P_MSGI) { SETPORT(SIMODE0, 0); SETPORT(SIMODE1, ENPHASEMIS|ENBUSFREE); #if defined(DEBUG_RACE) @@ -1509,63 +1658,59 @@ SETBITS(DMACNTRL0, INTEN); return; } - } + } /* Check, if we aren't busy with a command */ - if(!CURRENT_SC) - { - /* bus is free to issue a queued command */ - if(TESTHI(SSTAT1, BUSFREE) && ISSUE_SC) - { - save_flags(flags); - cli(); + if(!CURRENT_SC) { + /* bus is free to issue a queued command */ + if(TESTHI(SSTAT1, BUSFREE) && ISSUE_SC) { + save_flags(flags); + cli(); #if defined(DEBUG_QUEUES) - if(HOSTDATA(shpnt)->debug & debug_queues) - printk("i-, "); + if(HOSTDATA(shpnt)->debug & debug_queues) + printk("i-, "); #endif - CURRENT_SC = remove_first_SC(&ISSUE_SC); - restore_flags(flags); + CURRENT_SC = remove_first_SC(&ISSUE_SC); + restore_flags(flags); #if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_intr|debug_selection|debug_phases)) - printk("issuing command, "); + if(HOSTDATA(shpnt)->debug & (debug_intr|debug_selection|debug_phases)) + printk("issuing command, "); #endif - CURRENT_SC->SCp.phase = in_selection; + CURRENT_SC->SCp.phase = in_selection; #if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_intr|debug_selection|debug_phases)) - printk("selecting %d, ", CURRENT_SC->target); + if(HOSTDATA(shpnt)->debug & (debug_intr|debug_selection|debug_phases)) + printk("selecting %d, ", CURRENT_SC->target); #endif - SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target); + SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->target); - /* Enable interrupts for SELECTION OUT DONE and SELECTION OUT INITIATED */ - SETPORT(SXFRCTL1, HOSTDATA(shpnt)->parity ? (ENSPCHK|ENSTIMER) : ENSTIMER); + /* Enable interrupts for SELECTION OUT DONE and SELECTION OUT INITIATED */ + SETPORT(SXFRCTL1, HOSTDATA(shpnt)->parity ? (ENSPCHK|ENSTIMER) : ENSTIMER); - /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */ - SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0)); - SETPORT(SIMODE1, ENSELTIMO); + /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */ + SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0)); + SETPORT(SIMODE1, ENSELTIMO); - /* Enable SELECTION OUT sequence */ - SETBITS(SCSISEQ, ENSELO | ENAUTOATNO); - - } - else - { - /* No command we are busy with and no new to issue */ - printk("aha152x: ignoring spurious interrupt, nothing to do\n"); - if(TESTHI(DMACNTRL0, SWINT)) { - printk("aha152x: SWINT is set! Why?\n"); - CLRBITS(DMACNTRL0, SWINT); - } - show_queues(shpnt); - } + /* Enable SELECTION OUT sequence */ + SETBITS(SCSISEQ, ENSELO | ENAUTOATNO); + + } else { + /* No command we are busy with and no new to issue */ + printk("aha152x: ignoring spurious interrupt, nothing to do\n"); + if(TESTHI(DMACNTRL0, SWINT)) { + printk("aha152x: SWINT is set! Why?\n"); + CLRBITS(DMACNTRL0, SWINT); + } + show_queues(shpnt); + } #if defined(DEBUG_RACE) - leave_driver("(selecting) intr"); + leave_driver("(selecting) intr"); #endif - SETBITS(DMACNTRL0, INTEN); - return; - } + SETBITS(DMACNTRL0, INTEN); + return; + } /* the bus is busy with something */ @@ -1575,126 +1720,120 @@ #endif /* we are waiting for the result of a selection attempt */ - if(CURRENT_SC->SCp.phase & in_selection) - { - if(TESTLO(SSTAT1, SELTO)) - /* no timeout */ - if(TESTHI(SSTAT0, SELDO)) - { - /* clear BUS FREE interrupt */ - SETPORT(SSTAT1, CLRBUSFREE); - - /* Disable SELECTION OUT sequence */ - CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO); - - /* Disable SELECTION OUT DONE interrupt */ - CLRBITS(SIMODE0, ENSELDO); - CLRBITS(SIMODE1, ENSELTIMO); - - if(TESTLO(SSTAT0, SELDO)) - { - printk("aha152x: passing bus free condition\n"); + if(CURRENT_SC->SCp.phase & in_selection) { + if(TESTLO(SSTAT1, SELTO)) + /* no timeout */ + if(TESTHI(SSTAT0, SELDO)) { + /* clear BUS FREE interrupt */ + SETPORT(SSTAT1, CLRBUSFREE); + + /* Disable SELECTION OUT sequence */ + CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO); + + /* Disable SELECTION OUT DONE interrupt */ + CLRBITS(SIMODE0, ENSELDO); + CLRBITS(SIMODE1, ENSELTIMO); + + if(TESTLO(SSTAT0, SELDO)) { + printk("aha152x: passing bus free condition\n"); #if defined(DEBUG_RACE) - leave_driver("(passing bus free) intr"); + leave_driver("(passing bus free) intr"); #endif - SETBITS(DMACNTRL0, INTEN); + SETBITS(DMACNTRL0, INTEN); + + if(CURRENT_SC->SCp.phase & aborted) { + HOSTDATA(shpnt)->abort_result=SCSI_ABORT_ERROR; + HOSTDATA(shpnt)->abortion_complete++; + } - if(CURRENT_SC->SCp.phase & aborted) - { - HOSTDATA(shpnt)->abort_result=SCSI_ABORT_ERROR; - HOSTDATA(shpnt)->abortion_complete++; - } - - aha152x_done(shpnt, DID_NO_CONNECT << 16); - return; - } + aha152x_done(shpnt, DID_NO_CONNECT << 16); + + return; + } #if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_selection|debug_phases)) - printk("SELDO (SELID=%x), ", GETPORT(SELID)); + if(HOSTDATA(shpnt)->debug & (debug_selection|debug_phases)) + printk("SELDO (SELID=%x), ", GETPORT(SELID)); #endif - /* selection was done */ - SETPORT(SSTAT0, CLRSELDO); + /* selection was done */ + SETPORT(SSTAT0, CLRSELDO); #if defined(DEBUG_ABORT) - if((HOSTDATA(shpnt)->debug & debug_abort) && (CURRENT_SC->SCp.phase & aborted)) - printk("(ABORT) target selected, "); + if((HOSTDATA(shpnt)->debug & debug_abort) && (CURRENT_SC->SCp.phase & aborted)) + printk("(ABORT) target selected, "); #endif - CURRENT_SC->SCp.phase &= ~in_selection; - CURRENT_SC->SCp.phase |= in_other; + CURRENT_SC->SCp.phase &= ~in_selection; + CURRENT_SC->SCp.phase |= in_other; - ADDMSG(IDENTIFY(HOSTDATA(shpnt)->reconnect,CURRENT_SC->lun)); + ADDMSG(IDENTIFY(HOSTDATA(shpnt)->reconnect,CURRENT_SC->lun)); - if(!(SYNCRATE&0x80) && HOSTDATA(shpnt)->synchronous) - { - ADDMSG(EXTENDED_MESSAGE); - ADDMSG(3); - ADDMSG(EXTENDED_SDTR); - ADDMSG(50); - ADDMSG(8); + if(!(SYNCRATE&0x80) && HOSTDATA(shpnt)->synchronous) { + ADDMSG(EXTENDED_MESSAGE); + ADDMSG(3); + ADDMSG(EXTENDED_SDTR); + ADDMSG(50); + ADDMSG(8); - printk("outbound SDTR: "); - print_msg(&MSG(MSGLEN-5)); + printk("outbound SDTR: "); + print_msg(&MSG(MSGLEN-5)); - SYNCRATE=0x80; - CURRENT_SC->SCp.phase |= in_sync; - } + SYNCRATE=0x80; + CURRENT_SC->SCp.phase |= in_sync; + } #if defined(DEBUG_RACE) - leave_driver("(SELDO) intr"); + leave_driver("(SELDO) intr"); #endif - SETPORT(SCSIRATE, SYNCRATE&0x7f); + SETPORT(SCSIRATE, SYNCRATE&0x7f); - SETPORT(SCSISIG, P_MSGO); + SETPORT(SCSISIG, P_MSGO); - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENREQINIT|ENBUSFREE); - SETBITS(DMACNTRL0, INTEN); - return; - } - else - aha152x_panic(shpnt, "neither timeout nor selection\007"); - else - { -#if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_selection|debug_phases)) - printk("SELTO, "); + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENREQINIT|ENBUSFREE); + SETBITS(DMACNTRL0, INTEN); + + return; + } else + aha152x_panic(shpnt, "neither timeout nor selection\007"); + else { +#if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES) + if(HOSTDATA(shpnt)->debug & (debug_selection|debug_phases)) + printk("SELTO, "); #endif - /* end selection attempt */ - CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO); + /* end selection attempt */ + CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO); - /* timeout */ - SETPORT(SSTAT1, CLRSELTIMO); + /* timeout */ + SETPORT(SSTAT1, CLRSELTIMO); - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); - SETBITS(DMACNTRL0, INTEN); + SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); + SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); + SETBITS(DMACNTRL0, INTEN); #if defined(DEBUG_RACE) - leave_driver("(SELTO) intr"); + leave_driver("(SELTO) intr"); #endif - if(CURRENT_SC->SCp.phase & aborted) - { + if(CURRENT_SC->SCp.phase & aborted) { #if defined(DEBUG_ABORT) - if(HOSTDATA(shpnt)->debug & debug_abort) - printk("(ABORT) selection timeout, "); + if(HOSTDATA(shpnt)->debug & debug_abort) + printk("(ABORT) selection timeout, "); #endif - HOSTDATA(shpnt)->abort_result=SCSI_ABORT_ERROR; - HOSTDATA(shpnt)->abortion_complete++; - } - - if(TESTLO(SSTAT0, SELINGO)) - /* ARBITRATION not won */ - aha152x_done(shpnt, DID_BUS_BUSY << 16); - else - /* ARBITRATION won, but SELECTION failed */ - aha152x_done(shpnt, DID_NO_CONNECT << 16); + HOSTDATA(shpnt)->abort_result=SCSI_ABORT_ERROR; + HOSTDATA(shpnt)->abortion_complete++; + } - return; - } + if(TESTLO(SSTAT0, SELINGO)) + /* ARBITRATION not won */ + aha152x_done(shpnt, DID_BUS_BUSY << 16); + else + /* ARBITRATION won, but SELECTION failed */ + aha152x_done(shpnt, DID_NO_CONNECT << 16); + + return; } + } /* enable interrupt, when target leaves current phase */ phase = getphase(shpnt); @@ -1705,756 +1844,712 @@ (CURRENT_SC->SCp.phase & ~((P_MASK|1)<<16)) | (phase << 16); /* information transfer phase */ - switch(phase) + switch(phase) { + case P_MSGO: /* MESSAGE OUT */ { - case P_MSGO: /* MESSAGE OUT */ - { - int i, identify=0, abort=0; + int i, identify=0, abort=0; #if defined(DEBUG_INTR) || defined(DEBUG_MSGO) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_intr|debug_msgo|debug_phases)) - printk("MESSAGE OUT, "); + if(HOSTDATA(shpnt)->debug & (debug_intr|debug_msgo|debug_phases)) + printk("MESSAGE OUT, "); #endif - if(MSGLEN==0) - { - ADDMSG(MESSAGE_REJECT); + if(MSGLEN==0) { + ADDMSG(MESSAGE_REJECT); #if defined(DEBUG_MSGO) - if(HOSTDATA(shpnt)->debug & debug_msgo) - printk("unexpected MSGO; rejecting, "); + if(HOSTDATA(shpnt)->debug & debug_msgo) + printk("unexpected MESSAGE OUT phase; rejecting, "); #endif - } - + } - CLRBITS(SXFRCTL0, ENDMA); + CLRBITS(SXFRCTL0, ENDMA); - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENPHASEMIS|ENREQINIT|ENBUSFREE); + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENPHASEMIS|ENREQINIT|ENBUSFREE); - /* wait for data latch to become ready or a phase change */ - while(TESTLO(DMASTAT, INTSTAT)) - barrier(); + /* wait for data latch to become ready or a phase change */ + while(TESTLO(DMASTAT, INTSTAT)) + barrier(); #if defined(DEBUG_MSGO) - if(HOSTDATA(shpnt)->debug & debug_msgo) - { - int i; + if(HOSTDATA(shpnt)->debug & debug_msgo) { + int i; - printk("messages ("); - for(i=0; idebug & debug_msgo) - printk("%x ", MSG(i)); + if(HOSTDATA(shpnt)->debug & debug_msgo) + printk("%x ", MSG(i)); #endif - if(i==MSGLEN-1) - { - /* Leave MESSAGE OUT after transfer */ - SETPORT(SSTAT1, CLRATNO); - } - - SETPORT(SCSIDAT, MSG(i)); + if(i==MSGLEN-1) { + /* Leave MESSAGE OUT after transfer */ + SETPORT(SSTAT1, CLRATNO); + } + + SETPORT(SCSIDAT, MSG(i)); - make_acklow(shpnt); - getphase(shpnt); + make_acklow(shpnt); + getphase(shpnt); - if(MSG(i)==IDENTIFY(HOSTDATA(shpnt)->reconnect,CURRENT_SC->lun)) - identify++; + if(MSG(i)==IDENTIFY(HOSTDATA(shpnt)->reconnect,CURRENT_SC->lun)) + identify++; - if(MSG(i)==ABORT) - abort++; + if(MSG(i)==ABORT) + abort++; - } + } - MSGLEN=0; + MSGLEN=0; - if(identify) - CURRENT_SC->SCp.phase |= sent_ident; + if(identify) + CURRENT_SC->SCp.phase |= sent_ident; - if(abort) - { - /* revive abort(); abort() enables interrupts */ - HOSTDATA(shpnt)->abort_result=SCSI_ABORT_SUCCESS; - HOSTDATA(shpnt)->abortion_complete++; + if(abort) { + /* revive abort(); abort() enables interrupts */ + HOSTDATA(shpnt)->abort_result=SCSI_ABORT_SUCCESS; + HOSTDATA(shpnt)->abortion_complete++; - CURRENT_SC->SCp.phase &= ~(P_MASK<<16); + CURRENT_SC->SCp.phase &= ~(P_MASK<<16); - /* exit */ - SETBITS(DMACNTRL0, INTEN); + /* exit */ + SETBITS(DMACNTRL0, INTEN); #if defined(DEBUG_RACE) - leave_driver("(ABORT) intr"); + leave_driver("(ABORT) intr"); #endif - aha152x_done(shpnt, DID_ABORT<<16); - return; - } + aha152x_done(shpnt, DID_ABORT<<16); + + return; } - break; + } + break; - case P_CMD: /* COMMAND phase */ + case P_CMD: /* COMMAND phase */ #if defined(DEBUG_INTR) || defined(DEBUG_CMD) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_intr|debug_cmd|debug_phases)) - printk("COMMAND, "); + if(HOSTDATA(shpnt)->debug & (debug_intr|debug_cmd|debug_phases)) + printk("COMMAND, "); #endif - if(!(CURRENT_SC->SCp.sent_command)) - { - int i; + if(!(CURRENT_SC->SCp.sent_command)) { + int i; - CLRBITS(SXFRCTL0, ENDMA); + CLRBITS(SXFRCTL0, ENDMA); - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENPHASEMIS|ENREQINIT|ENBUSFREE); + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENPHASEMIS|ENREQINIT|ENBUSFREE); - /* wait for data latch to become ready or a phase change */ - while(TESTLO(DMASTAT, INTSTAT)) - barrier(); + /* wait for data latch to become ready or a phase change */ + while(TESTLO(DMASTAT, INTSTAT)) + barrier(); - for(i=0; icmd_len && TESTLO(SSTAT1, PHASEMIS); i++) - { - SETPORT(SCSIDAT, CURRENT_SC->cmnd[i]); - - make_acklow(shpnt); - getphase(shpnt); - } + for(i=0; icmd_len && TESTLO(SSTAT1, PHASEMIS); i++) { + SETPORT(SCSIDAT, CURRENT_SC->cmnd[i]); - if(icmd_len && TESTHI(SSTAT1, PHASEMIS)) - aha152x_panic(shpnt, "target left COMMAND"); + make_acklow(shpnt); + getphase(shpnt); + } - CURRENT_SC->SCp.sent_command++; - } - else - aha152x_panic(shpnt, "Nothing to send while in COMMAND"); + if(icmd_len && TESTHI(SSTAT1, PHASEMIS)) + aha152x_panic(shpnt, "target left COMMAND"); + + CURRENT_SC->SCp.sent_command++; + } else + aha152x_panic(shpnt, "Nothing to send while in COMMAND"); break; - case P_MSGI: /* MESSAGE IN phase */ - { - int start_sync=0; + case P_MSGI: /* MESSAGE IN phase */ + { + int start_sync=0; #if defined(DEBUG_INTR) || defined(DEBUG_MSGI) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_intr|debug_msgi|debug_phases)) - printk("MESSAGE IN, "); + if(HOSTDATA(shpnt)->debug & (debug_intr|debug_msgi|debug_phases)) + printk("MESSAGE IN, "); #endif - SETPORT(SXFRCTL0, CH1); + SETPORT(SXFRCTL0, CH1); - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENBUSFREE); + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENBUSFREE); - while(phase == P_MSGI) - { - CURRENT_SC->SCp.Message = GETPORT(SCSIDAT); - switch(CURRENT_SC->SCp.Message) - { - case DISCONNECT: + while(phase == P_MSGI) { + CURRENT_SC->SCp.Message = GETPORT(SCSIDAT); + switch(CURRENT_SC->SCp.Message) { + case DISCONNECT: #if defined(DEBUG_MSGI) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_msgi|debug_phases)) - printk("target disconnected, "); + if(HOSTDATA(shpnt)->debug & (debug_msgi|debug_phases)) + printk("target disconnected, "); #endif - CURRENT_SC->SCp.Message = 0; - CURRENT_SC->SCp.phase |= disconnected; - if(!HOSTDATA(shpnt)->reconnect) - aha152x_panic(shpnt, "target was not allowed to disconnect"); - break; - - case COMMAND_COMPLETE: + CURRENT_SC->SCp.Message = 0; + CURRENT_SC->SCp.phase |= disconnected; + if(!HOSTDATA(shpnt)->reconnect) + aha152x_panic(shpnt, "target was not allowed to disconnect"); + + break; + + case COMMAND_COMPLETE: #if defined(DEBUG_MSGI) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_msgi|debug_phases)) - printk("inbound message (COMMAND COMPLETE), "); + if(HOSTDATA(shpnt)->debug & (debug_msgi|debug_phases)) + printk("inbound message (COMMAND COMPLETE), "); #endif - done++; - break; + done++; + break; - case MESSAGE_REJECT: - if(CURRENT_SC->SCp.phase & in_sync) - { - CURRENT_SC->SCp.phase &= ~in_sync; - SYNCRATE=0x80; - printk("synchronous rejected, "); - } - else - printk("inbound message (MESSAGE REJECT), "); + case MESSAGE_REJECT: + if(CURRENT_SC->SCp.phase & in_sync) { + CURRENT_SC->SCp.phase &= ~in_sync; + SYNCRATE=0x80; + printk("synchronous rejected, "); + } else + printk("inbound message (MESSAGE REJECT), "); #if defined(DEBUG_MSGI) - if(HOSTDATA(shpnt)->debug & debug_msgi) - printk("inbound message (MESSAGE REJECT), "); + if(HOSTDATA(shpnt)->debug & debug_msgi) + printk("inbound message (MESSAGE REJECT), "); #endif - break; + break; - case SAVE_POINTERS: + case SAVE_POINTERS: #if defined(DEBUG_MSGI) - if(HOSTDATA(shpnt)->debug & debug_msgi) - printk("inbound message (SAVE DATA POINTERS), "); + if(HOSTDATA(shpnt)->debug & debug_msgi) + printk("inbound message (SAVE DATA POINTERS), "); #endif - break; + break; - case RESTORE_POINTERS: + case RESTORE_POINTERS: #if defined(DEBUG_MSGI) - if(HOSTDATA(shpnt)->debug & debug_msgi) - printk("inbound message (RESTORE DATA POINTERS), "); + if(HOSTDATA(shpnt)->debug & debug_msgi) + printk("inbound message (RESTORE DATA POINTERS), "); #endif - break; + break; - case EXTENDED_MESSAGE: - { - char buffer[16]; - int i; + case EXTENDED_MESSAGE: + { + char buffer[16]; + int i; #if defined(DEBUG_MSGI) - if(HOSTDATA(shpnt)->debug & debug_msgi) - printk("inbound message (EXTENDED MESSAGE), "); + if(HOSTDATA(shpnt)->debug & debug_msgi) + printk("inbound message (EXTENDED MESSAGE), "); #endif - make_acklow(shpnt); - if(getphase(shpnt)!=P_MSGI) - break; - - buffer[0]=EXTENDED_MESSAGE; - buffer[1]=GETPORT(SCSIDAT); - - for(i=0; idebug & debug_msgi) - print_msg(buffer); + if(HOSTDATA(shpnt)->debug & debug_msgi) + print_msg(buffer); #endif - switch(buffer [2]) - { - case EXTENDED_SDTR: - { - long ticks; - - if(buffer[1]!=3) - aha152x_panic(shpnt, "SDTR message length != 3"); - - if(!HOSTDATA(shpnt)->synchronous) - break; - - printk("inbound SDTR: "); print_msg(buffer); - - ticks=(buffer[3]*4+49)/50; - - if(CURRENT_SC->SCp.phase & in_sync) - { - /* we initiated SDTR */ - if(ticks>9 || buffer[4]<1 || buffer[4]>8) - aha152x_panic(shpnt, "received SDTR invalid"); - - SYNCRATE |= ((ticks-2)<<4) + buffer[4]; - } - else if(ticks<=9 && buffer[4]>=1) - { - if(buffer[4]>8) - buffer[4]=8; - - ADDMSG(EXTENDED_MESSAGE); - ADDMSG(3); - ADDMSG(EXTENDED_SDTR); - if(ticks<4) - { - ticks=4; - ADDMSG(50); - } - else - ADDMSG(buffer[3]); - - ADDMSG(buffer[4]); - - printk("outbound SDTR: "); - print_msg(&MSG(MSGLEN-5)); - - CURRENT_SC->SCp.phase |= in_sync; - - SYNCRATE |= ((ticks-2)<<4) + buffer[4]; - - start_sync++; - } - else - { - /* requested SDTR is too slow, do it asynchronously */ - ADDMSG(MESSAGE_REJECT); - SYNCRATE = 0; - } - - SETPORT(SCSIRATE, SYNCRATE&0x7f); - } - break; - - case EXTENDED_MODIFY_DATA_POINTER: - case EXTENDED_EXTENDED_IDENTIFY: - case EXTENDED_WDTR: - default: - ADDMSG(MESSAGE_REJECT); - break; - } - } - break; + switch(buffer [2]) { + case EXTENDED_SDTR: + { + long ticks; + + if(buffer[1]!=3) + aha152x_panic(shpnt, "SDTR message length != 3"); + + if(!HOSTDATA(shpnt)->synchronous) + break; + + printk("inbound SDTR: "); print_msg(buffer); + + ticks=(buffer[3]*4+49)/50; + + if(CURRENT_SC->SCp.phase & in_sync) { + /* we initiated SDTR */ + if(ticks>9 || buffer[4]<1 || buffer[4]>8) + aha152x_panic(shpnt, "received SDTR invalid"); + + SYNCRATE |= ((ticks-2)<<4) + buffer[4]; + } else if(ticks<=9 && buffer[4]>=1) { + if(buffer[4]>8) + buffer[4]=8; + + ADDMSG(EXTENDED_MESSAGE); + ADDMSG(3); + ADDMSG(EXTENDED_SDTR); + if(ticks<4) { + ticks=4; + ADDMSG(50); + } else + ADDMSG(buffer[3]); + + ADDMSG(buffer[4]); + + printk("outbound SDTR: "); + print_msg(&MSG(MSGLEN-5)); + + CURRENT_SC->SCp.phase |= in_sync; + + SYNCRATE |= ((ticks-2)<<4) + buffer[4]; + + start_sync++; + } else { + /* requested SDTR is too slow, do it asynchronously */ + ADDMSG(MESSAGE_REJECT); + SYNCRATE = 0; + } + + SETPORT(SCSIRATE, SYNCRATE&0x7f); + } + break; + + case EXTENDED_MODIFY_DATA_POINTER: + case EXTENDED_EXTENDED_IDENTIFY: + case EXTENDED_WDTR: + default: + ADDMSG(MESSAGE_REJECT); + break; + } + } + break; - default: - printk("unsupported inbound message %x, ", - CURRENT_SC->SCp.Message); - break; + default: + printk("unsupported inbound message %x, ", CURRENT_SC->SCp.Message); + break; - } + } - make_acklow(shpnt); - phase=getphase(shpnt); - } + make_acklow(shpnt); + phase=getphase(shpnt); + } - if(start_sync) - CURRENT_SC->SCp.phase |= in_sync; - else - CURRENT_SC->SCp.phase &= ~in_sync; + if(start_sync) + CURRENT_SC->SCp.phase |= in_sync; + else + CURRENT_SC->SCp.phase &= ~in_sync; - if(MSGLEN>0) - SETPORT(SCSISIG, P_MSGI|ATNO); + if(MSGLEN>0) + SETPORT(SCSISIG, P_MSGI|ATNO); /* clear SCSI fifo on BUSFREE */ if(phase==P_BUSFREE) - SETPORT(SXFRCTL0, CH1|CLRCH1); + SETPORT(SXFRCTL0, CH1|CLRCH1); - if(CURRENT_SC->SCp.phase & disconnected) - { - save_flags(flags); - cli(); + if(CURRENT_SC->SCp.phase & disconnected) { + save_flags(flags); + cli(); #if defined(DEBUG_QUEUES) - if(HOSTDATA(shpnt)->debug & debug_queues) - printk("d+, "); + if(HOSTDATA(shpnt)->debug & debug_queues) + printk("d+, "); #endif - append_SC(&DISCONNECTED_SC, CURRENT_SC); - CURRENT_SC->SCp.phase |= 1<<16; - CURRENT_SC = NULL; - restore_flags(flags); - - SETBITS(SCSISEQ, ENRESELI); - - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); - - SETBITS(DMACNTRL0, INTEN); - return; - } + append_SC(&DISCONNECTED_SC, CURRENT_SC); + CURRENT_SC->SCp.phase |= 1<<16; + CURRENT_SC = NULL; + restore_flags(flags); + + SETBITS(SCSISEQ, ENRESELI); + + SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); + SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); + + SETBITS(DMACNTRL0, INTEN); + + return; } - break; + } + break; - case P_STATUS: /* STATUS IN phase */ + case P_STATUS: /* STATUS IN phase */ #if defined(DEBUG_STATUS) || defined(DEBUG_INTR) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_status|debug_intr|debug_phases)) - printk("STATUS, "); + if(HOSTDATA(shpnt)->debug & (debug_status|debug_intr|debug_phases)) + printk("STATUS, "); #endif - SETPORT(SXFRCTL0, CH1); + SETPORT(SXFRCTL0, CH1); - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENREQINIT|ENBUSFREE); + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENREQINIT|ENBUSFREE); - if(TESTHI(SSTAT1, PHASEMIS)) - printk("aha152x: passing STATUS phase"); - - CURRENT_SC->SCp.Status = GETPORT(SCSIBUS); - make_acklow(shpnt); - getphase(shpnt); + if(TESTHI(SSTAT1, PHASEMIS)) + printk("aha152x: passing STATUS phase"); + + CURRENT_SC->SCp.Status = GETPORT(SCSIBUS); + make_acklow(shpnt); + getphase(shpnt); #if defined(DEBUG_STATUS) - if(HOSTDATA(shpnt)->debug & debug_status) - { - printk("inbound status "); - print_status(CURRENT_SC->SCp.Status); - printk(", "); - } + if(HOSTDATA(shpnt)->debug & debug_status) { + printk("inbound status "); + print_status(CURRENT_SC->SCp.Status); + printk(", "); + } #endif - break; + break; - case P_DATAI: /* DATA IN phase */ - { - int fifodata, data_count, done; + case P_DATAI: /* DATA IN phase */ + { + int fifodata, data_count, done; #if defined(DEBUG_DATAI) || defined(DEBUG_INTR) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_datai|debug_intr|debug_phases)) - printk("DATA IN, "); + if(HOSTDATA(shpnt)->debug & (debug_datai|debug_intr|debug_phases)) + printk("DATA IN, "); #endif #if 0 - if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT)) - printk("aha152x: P_DATAI: %d(%d) bytes left in FIFO, resetting\n", - GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT)); + if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT)) + printk("aha152x: P_DATAI: %d(%d) bytes left in FIFO, resetting\n", + GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT)); #endif - /* reset host fifo */ - SETPORT(DMACNTRL0, RSTFIFO); - SETPORT(DMACNTRL0, RSTFIFO|ENDMA); + /* reset host fifo */ + SETPORT(DMACNTRL0, RSTFIFO); + SETPORT(DMACNTRL0, RSTFIFO|ENDMA); - SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN); + SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN); - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENPHASEMIS|ENBUSFREE); + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENPHASEMIS|ENBUSFREE); - /* done is set when the FIFO is empty after the target left DATA IN */ - done=0; + /* done is set when the FIFO is empty after the target left DATA IN */ + done=0; - /* while the target stays in DATA to transfer data */ - while (!done) - { + /* while the target stays in DATA to transfer data */ + while (!done) { #if defined(DEBUG_DATAI) - if(HOSTDATA(shpnt)->debug & debug_datai) - printk("expecting data, "); + if(HOSTDATA(shpnt)->debug & debug_datai) + printk("expecting data, "); #endif - /* wait for PHASEMIS or full FIFO */ - while(TESTLO (DMASTAT, DFIFOFULL|INTSTAT)) - barrier(); + /* wait for PHASEMIS or full FIFO */ + while(TESTLO(DMASTAT, DFIFOFULL|INTSTAT)) + barrier(); #if defined(DEBUG_DATAI) - if(HOSTDATA(shpnt)->debug & debug_datai) - printk("ok, "); + if(HOSTDATA(shpnt)->debug & debug_datai) + printk("ok, "); #endif - - if(TESTHI(DMASTAT, DFIFOFULL)) - fifodata=GETPORT(FIFOSTAT); - else - { - /* wait for SCSI fifo to get empty */ - while(TESTLO(SSTAT2, SEMPTY)) - barrier(); + + if(TESTHI(DMASTAT, DFIFOFULL)) + fifodata=GETPORT(FIFOSTAT); + else { + /* wait for SCSI fifo to get empty */ + while(TESTLO(SSTAT2, SEMPTY)) + barrier(); - /* rest of data in FIFO */ - fifodata=GETPORT(FIFOSTAT); + /* rest of data in FIFO */ + fifodata=GETPORT(FIFOSTAT); #if defined(DEBUG_DATAI) - if(HOSTDATA(shpnt)->debug & debug_datai) - printk("last transfer, "); + if(HOSTDATA(shpnt)->debug & debug_datai) + printk("last transfer, "); #endif - done=1; - } + done=1; + } #if defined(DEBUG_DATAI) - if(HOSTDATA(shpnt)->debug & debug_datai) - printk("fifodata=%d, ", fifodata); + if(HOSTDATA(shpnt)->debug & debug_datai) + printk("fifodata=%d, ", fifodata); #endif - while(fifodata && CURRENT_SC->SCp.this_residual) - { - data_count=fifodata; + while(fifodata && CURRENT_SC->SCp.this_residual) { + data_count=fifodata; - /* limit data transfer to size of first sg buffer */ - if (data_count > CURRENT_SC->SCp.this_residual) - data_count = CURRENT_SC->SCp.this_residual; + /* limit data transfer to size of first sg buffer */ + if(data_count > CURRENT_SC->SCp.this_residual) + data_count = CURRENT_SC->SCp.this_residual; - fifodata -= data_count; + fifodata -= data_count; #if defined(DEBUG_DATAI) - if(HOSTDATA(shpnt)->debug & debug_datai) - printk("data_count=%d, ", data_count); + if(HOSTDATA(shpnt)->debug & debug_datai) + printk("data_count=%d, ", data_count); #endif - if(data_count&1) - { - /* get a single byte in byte mode */ - SETBITS(DMACNTRL0, _8BIT); - *CURRENT_SC->SCp.ptr++ = GETPORT(DATAPORT); - CURRENT_SC->SCp.this_residual--; - } - if(data_count>1) - { - CLRBITS(DMACNTRL0, _8BIT); - data_count >>= 1; /* Number of words */ - insw(DATAPORT, CURRENT_SC->SCp.ptr, data_count); -#if defined(DEBUG_DATAI) - if(HOSTDATA(shpnt)->debug & debug_datai) - /* show what comes with the last transfer */ - if(done) - { -#ifdef 0 - int i; - unsigned char *data; -#endif - - printk("data on last transfer (%d bytes) ", - 2*data_count); -#ifdef 0 - printk("data on last transfer (%d bytes: ", - 2*data_count); - data = (unsigned char *) CURRENT_SC->SCp.ptr; - for(i=0; i<2*data_count; i++) - printk("%2x ", *data++); - printk("), "); -#endif - } -#endif - CURRENT_SC->SCp.ptr += 2 * data_count; - CURRENT_SC->SCp.this_residual -= 2 * data_count; - } - - /* if this buffer is full and there are more buffers left */ - if (!CURRENT_SC->SCp.this_residual && - CURRENT_SC->SCp.buffers_residual) - { - /* advance to next buffer */ - CURRENT_SC->SCp.buffers_residual--; - CURRENT_SC->SCp.buffer++; - CURRENT_SC->SCp.ptr = - CURRENT_SC->SCp.buffer->address; - CURRENT_SC->SCp.this_residual = - CURRENT_SC->SCp.buffer->length; - } - } + if(data_count&1) { + /* get a single byte in byte mode */ + SETBITS(DMACNTRL0, _8BIT); + *CURRENT_SC->SCp.ptr++ = GETPORT(DATAPORT); + CURRENT_SC->SCp.this_residual--; + } - /* - * Fifo should be empty - */ - if(fifodata>0) - { - printk("aha152x: more data than expected (%d bytes)\n", - GETPORT(FIFOSTAT)); - SETBITS(DMACNTRL0, _8BIT); - printk("aha152x: data ("); - while(fifodata--) - printk("%2x ", GETPORT(DATAPORT)); - printk(")\n"); - } - + if(data_count>1) { + CLRBITS(DMACNTRL0, _8BIT); + data_count >>= 1; /* Number of words */ + insw(DATAPORT, CURRENT_SC->SCp.ptr, data_count); #if defined(DEBUG_DATAI) if(HOSTDATA(shpnt)->debug & debug_datai) - if(!fifodata) - printk("fifo empty, "); - else - printk("something left in fifo, "); + /* show what comes with the last transfer */ + if(done) { +#if 0 + int i; + unsigned char *data; #endif - } + + printk("data on last transfer (%d bytes) ", + 2*data_count); +#if 0 + printk("data on last transfer (%d bytes: ", + 2*data_count); + data = (unsigned char *) CURRENT_SC->SCp.ptr; + for(i=0; i<2*data_count; i++) + printk("%2x ", *data++); + printk("), "); +#endif + } +#endif + CURRENT_SC->SCp.ptr += 2 * data_count; + CURRENT_SC->SCp.this_residual -= 2 * data_count; + } + + /* if this buffer is full and there are more buffers left */ + if(!CURRENT_SC->SCp.this_residual && + CURRENT_SC->SCp.buffers_residual) { + /* advance to next buffer */ + CURRENT_SC->SCp.buffers_residual--; + CURRENT_SC->SCp.buffer++; + CURRENT_SC->SCp.ptr = CURRENT_SC->SCp.buffer->address; + CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length; + } + } + + /* + * FIFO should be empty + */ + if(fifodata>0) { + printk("aha152x: more data than expected (%d bytes)\n", + GETPORT(FIFOSTAT)); + SETBITS(DMACNTRL0, _8BIT); + printk("aha152x: data ("); + while(fifodata--) + printk("%2x ", GETPORT(DATAPORT)); + printk(")\n"); + } #if defined(DEBUG_DATAI) - if((HOSTDATA(shpnt)->debug & debug_datai) && - (CURRENT_SC->SCp.buffers_residual || - CURRENT_SC->SCp.this_residual)) - printk("left buffers (buffers=%d, bytes=%d), ", - CURRENT_SC->SCp.buffers_residual, - CURRENT_SC->SCp.this_residual); + if(HOSTDATA(shpnt)->debug & debug_datai) + if(!fifodata) + printk("fifo empty, "); + else + printk("something left in fifo, "); #endif - /* transfer can be considered ended, when SCSIEN reads back zero */ - CLRBITS(SXFRCTL0, SCSIEN|DMAEN); - while(TESTHI(SXFRCTL0, SCSIEN)) - barrier(); - CLRBITS(DMACNTRL0, ENDMA); + } + +#if defined(DEBUG_DATAI) + if((HOSTDATA(shpnt)->debug & debug_datai) && + (CURRENT_SC->SCp.buffers_residual || + CURRENT_SC->SCp.this_residual)) + printk("left buffers (buffers=%d, bytes=%d), ", + CURRENT_SC->SCp.buffers_residual, CURRENT_SC->SCp.this_residual); +#endif + /* transfer can be considered ended, when SCSIEN reads back zero */ + CLRBITS(SXFRCTL0, SCSIEN|DMAEN); + while(TESTHI(SXFRCTL0, SCSIEN)) + barrier(); + CLRBITS(DMACNTRL0, ENDMA); #if defined(DEBUG_DATAI) || defined(DEBUG_INTR) - if(HOSTDATA(shpnt)->debug & (debug_datai|debug_intr)) - printk("got %d bytes, ", GETSTCNT()); + if(HOSTDATA(shpnt)->debug & (debug_datai|debug_intr)) + printk("got %d bytes, ", GETSTCNT()); #endif - CURRENT_SC->SCp.have_data_in++; - } - break; + CURRENT_SC->SCp.have_data_in++; + } + break; - case P_DATAO: /* DATA OUT phase */ - { - int data_count; + case P_DATAO: /* DATA OUT phase */ + { + int data_count; #if defined(DEBUG_DATAO) || defined(DEBUG_INTR) || defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & (debug_datao|debug_intr|debug_phases)) - printk("DATA OUT, "); + if(HOSTDATA(shpnt)->debug & (debug_datao|debug_intr|debug_phases)) + printk("DATA OUT, "); #endif #if defined(DEBUG_DATAO) - if(HOSTDATA(shpnt)->debug & debug_datao) - printk("got data to send (bytes=%d, buffers=%d), ", - CURRENT_SC->SCp.this_residual, - CURRENT_SC->SCp.buffers_residual); + if(HOSTDATA(shpnt)->debug & debug_datao) + printk("got data to send (bytes=%d, buffers=%d), ", + CURRENT_SC->SCp.this_residual, + CURRENT_SC->SCp.buffers_residual); #endif - if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT)) - { - printk("%d(%d) left in FIFO, ", - GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT)); - aha152x_panic(shpnt, "FIFO should be empty"); - } + if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT)) { + printk("%d(%d) left in FIFO, ", + GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT)); + aha152x_panic(shpnt, "FIFO should be empty"); + } - SETPORT(SXFRCTL0, CH1|CLRSTCNT|CLRCH1); - SETPORT(SXFRCTL0, SCSIEN|DMAEN|CH1); + SETPORT(SXFRCTL0, CH1|CLRSTCNT|CLRCH1); + SETPORT(SXFRCTL0, SCSIEN|DMAEN|CH1); - SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO); - SETPORT(DMACNTRL0, ENDMA|WRITE_READ); + SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO); + SETPORT(DMACNTRL0, ENDMA|WRITE_READ); - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENPHASEMIS|ENBUSFREE); + SETPORT(SIMODE0, 0); + SETPORT(SIMODE1, ENPHASEMIS|ENBUSFREE); - /* while current buffer is not empty or - there are more buffers to transfer */ - while(TESTLO(SSTAT1, PHASEMIS) && - (CURRENT_SC->SCp.this_residual || - CURRENT_SC->SCp.buffers_residual)) - { + /* while current buffer is not empty or + there are more buffers to transfer */ + while(TESTLO(SSTAT1, PHASEMIS) && + (CURRENT_SC->SCp.this_residual || + CURRENT_SC->SCp.buffers_residual)) { #if defined(DEBUG_DATAO) - if(HOSTDATA(shpnt)->debug & debug_datao) - printk("sending data (left: bytes=%d, buffers=%d), waiting, ", - CURRENT_SC->SCp.this_residual, - CURRENT_SC->SCp.buffers_residual); -#endif - /* transfer rest of buffer, but max. 128 byte */ - data_count = - CURRENT_SC->SCp.this_residual > 128 ? - 128 : CURRENT_SC->SCp.this_residual ; + if(HOSTDATA(shpnt)->debug & debug_datao) + printk("sending data (left: bytes=%d, buffers=%d), waiting, ", + CURRENT_SC->SCp.this_residual, + CURRENT_SC->SCp.buffers_residual); +#endif + /* transfer rest of buffer, but max. 128 byte */ + data_count = + CURRENT_SC->SCp.this_residual > 128 ? + 128 : CURRENT_SC->SCp.this_residual ; #if defined(DEBUG_DATAO) - if(HOSTDATA(shpnt)->debug & debug_datao) - printk("data_count=%d, ", data_count); + if(HOSTDATA(shpnt)->debug & debug_datao) + printk("data_count=%d, ", data_count); #endif - if(data_count&1) - { - /* put a single byte in byte mode */ - SETBITS(DMACNTRL0, _8BIT); - SETPORT(DATAPORT, *CURRENT_SC->SCp.ptr++); - CURRENT_SC->SCp.this_residual--; - } - if(data_count>1) - { - CLRBITS(DMACNTRL0, _8BIT); - data_count >>= 1; /* number of words */ - outsw(DATAPORT, CURRENT_SC->SCp.ptr, data_count); - CURRENT_SC->SCp.ptr += 2 * data_count; - CURRENT_SC->SCp.this_residual -= 2 * data_count; - } - - /* wait for FIFO to get empty */ - while(TESTLO(DMASTAT, DFIFOEMP|INTSTAT)) - barrier(); + if(data_count&1) { + /* put a single byte in byte mode */ + SETBITS(DMACNTRL0, _8BIT); + SETPORT(DATAPORT, *CURRENT_SC->SCp.ptr++); + CURRENT_SC->SCp.this_residual--; + } + if(data_count>1) { + CLRBITS(DMACNTRL0, _8BIT); + data_count >>= 1; /* number of words */ + outsw(DATAPORT, CURRENT_SC->SCp.ptr, data_count); + CURRENT_SC->SCp.ptr += 2 * data_count; + CURRENT_SC->SCp.this_residual -= 2 * data_count; + } + + /* wait for FIFO to get empty */ + while(TESTLO(DMASTAT, DFIFOEMP|INTSTAT)) + barrier(); #if defined(DEBUG_DATAO) - if(HOSTDATA(shpnt)->debug & debug_datao) - printk("fifo (%d bytes), transfered (%d bytes), ", - GETPORT(FIFOSTAT), GETSTCNT()); -#endif - - /* if this buffer is empty and there are more buffers left */ - if (TESTLO(SSTAT1, PHASEMIS) && - !CURRENT_SC->SCp.this_residual && - CURRENT_SC->SCp.buffers_residual) - { - /* advance to next buffer */ - CURRENT_SC->SCp.buffers_residual--; - CURRENT_SC->SCp.buffer++; - CURRENT_SC->SCp.ptr = - CURRENT_SC->SCp.buffer->address; - CURRENT_SC->SCp.this_residual = - CURRENT_SC->SCp.buffer->length; - } - } - - if (CURRENT_SC->SCp.this_residual || CURRENT_SC->SCp.buffers_residual) - { - /* target leaves DATA OUT for an other phase - (perhaps disconnect) */ - - /* data in fifos has to be resend */ - data_count = GETPORT(SSTAT2) & (SFULL|SFCNT); - - data_count += GETPORT(FIFOSTAT) ; - CURRENT_SC->SCp.ptr -= data_count; - CURRENT_SC->SCp.this_residual += data_count; + if(HOSTDATA(shpnt)->debug & debug_datao) + printk("fifo (%d bytes), transfered (%d bytes), ", + GETPORT(FIFOSTAT), GETSTCNT()); +#endif + + /* if this buffer is empty and there are more buffers left */ + if(TESTLO(SSTAT1, PHASEMIS) && + !CURRENT_SC->SCp.this_residual && + CURRENT_SC->SCp.buffers_residual) { + /* advance to next buffer */ + CURRENT_SC->SCp.buffers_residual--; + CURRENT_SC->SCp.buffer++; + CURRENT_SC->SCp.ptr = CURRENT_SC->SCp.buffer->address; + CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length; + } + } + + if(CURRENT_SC->SCp.this_residual || CURRENT_SC->SCp.buffers_residual) { + /* target leaves DATA OUT for an other phase (perhaps disconnect) */ + + /* data in fifos has to be resend */ + data_count = GETPORT(SSTAT2) & (SFULL|SFCNT); + + data_count += GETPORT(FIFOSTAT) ; + CURRENT_SC->SCp.ptr -= data_count; + CURRENT_SC->SCp.this_residual += data_count; #if defined(DEBUG_DATAO) - if(HOSTDATA(shpnt)->debug & debug_datao) - printk("left data (bytes=%d, buffers=%d), fifos (bytes=%d), " - "transfer incomplete, resetting fifo, ", - CURRENT_SC->SCp.this_residual, - CURRENT_SC->SCp.buffers_residual, - data_count); -#endif - SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO); - CLRBITS(SXFRCTL0, SCSIEN|DMAEN); - CLRBITS(DMACNTRL0, ENDMA); - } - else - { + if(HOSTDATA(shpnt)->debug & debug_datao) + printk("left data (bytes=%d, buffers=%d), fifos (bytes=%d), " + "transfer incomplete, resetting fifo, ", + CURRENT_SC->SCp.this_residual, + CURRENT_SC->SCp.buffers_residual, + data_count); +#endif + SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO); + CLRBITS(SXFRCTL0, SCSIEN|DMAEN); + CLRBITS(DMACNTRL0, ENDMA); + } else { #if defined(DEBUG_DATAO) - if(HOSTDATA(shpnt)->debug & debug_datao) - printk("waiting for SCSI fifo to get empty, "); + if(HOSTDATA(shpnt)->debug & debug_datao) + printk("waiting for SCSI fifo to get empty, "); #endif - /* wait for SCSI fifo to get empty */ - while(TESTLO(SSTAT2, SEMPTY)) - barrier(); + /* wait for SCSI fifo to get empty */ + while(TESTLO(SSTAT2, SEMPTY)) + barrier(); #if defined(DEBUG_DATAO) - if(HOSTDATA(shpnt)->debug & debug_datao) - printk("ok, left data (bytes=%d, buffers=%d) ", - CURRENT_SC->SCp.this_residual, - CURRENT_SC->SCp.buffers_residual); -#endif - CLRBITS(SXFRCTL0, SCSIEN|DMAEN); - - /* transfer can be considered ended, when SCSIEN reads back zero */ - while(TESTHI(SXFRCTL0, SCSIEN)) - barrier(); + if(HOSTDATA(shpnt)->debug & debug_datao) + printk("ok, left data (bytes=%d, buffers=%d) ", + CURRENT_SC->SCp.this_residual, + CURRENT_SC->SCp.buffers_residual); +#endif + CLRBITS(SXFRCTL0, SCSIEN|DMAEN); - CLRBITS(DMACNTRL0, ENDMA); - } + /* transfer can be considered ended, when SCSIEN reads back zero */ + while(TESTHI(SXFRCTL0, SCSIEN)) + barrier(); + + CLRBITS(DMACNTRL0, ENDMA); + } #if defined(DEBUG_DATAO) || defined(DEBUG_INTR) - if(HOSTDATA(shpnt)->debug & (debug_datao|debug_intr)) - printk("sent %d data bytes, ", GETSTCNT()); + if(HOSTDATA(shpnt)->debug & (debug_datao|debug_intr)) + printk("sent %d data bytes, ", GETSTCNT()); #endif - } - break; + } + break; - case P_BUSFREE: /* BUSFREE */ + case P_BUSFREE: /* BUSFREE */ #if defined(DEBUG_RACE) - leave_driver("(BUSFREE) intr"); + leave_driver("(BUSFREE) intr"); #endif #if defined(DEBUG_PHASES) - if(HOSTDATA(shpnt)->debug & debug_phases) - printk("unexpected BUS FREE, "); + if(HOSTDATA(shpnt)->debug & debug_phases) + printk("unexpected BUS FREE, "); #endif - CURRENT_SC->SCp.phase &= ~(P_MASK<<16); + CURRENT_SC->SCp.phase &= ~(P_MASK<<16); - aha152x_done(shpnt, DID_ERROR << 16); /* Don't know any better */ - return; - break; + aha152x_done(shpnt, DID_ERROR << 16); /* Don't know any better */ + return; + break; - case P_PARITY: /* parity error in DATA phase */ + case P_PARITY: /* parity error in DATA phase */ #if defined(DEBUG_RACE) - leave_driver("(DID_PARITY) intr"); + leave_driver("(DID_PARITY) intr"); #endif - printk("PARITY error in DATA phase, "); + printk("PARITY error in DATA phase, "); - CURRENT_SC->SCp.phase &= ~(P_MASK<<16); + CURRENT_SC->SCp.phase &= ~(P_MASK<<16); - SETBITS(DMACNTRL0, INTEN); - aha152x_done(shpnt, DID_PARITY << 16); - return; - break; + SETBITS(DMACNTRL0, INTEN); + aha152x_done(shpnt, DID_PARITY << 16); + return; + break; - default: - printk("aha152x: unexpected phase\n"); - break; - } + default: + printk("aha152x: unexpected phase\n"); + break; + } - if(done) - { + if(done) { #if defined(DEBUG_INTR) - if(HOSTDATA(shpnt)->debug & debug_intr) - printk("command done.\n"); + if(HOSTDATA(shpnt)->debug & debug_intr) + printk("command done.\n"); #endif #if defined(DEBUG_RACE) - leave_driver("(done) intr"); + leave_driver("(done) intr"); #endif - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); - SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0); + SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); + SETPORT(SIMODE1, ISSUE_SC ? ENBUSFREE : 0); + SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0); + + SETBITS(DMACNTRL0, INTEN); - SETBITS(DMACNTRL0, INTEN); - - aha152x_done(shpnt, - (CURRENT_SC->SCp.Status & 0xff) - | ((CURRENT_SC->SCp.Message & 0xff) << 8) - | (DID_OK << 16)); + aha152x_done(shpnt, + (CURRENT_SC->SCp.Status & 0xff) + | ((CURRENT_SC->SCp.Message & 0xff) << 8) + | (DID_OK << 16)); #if defined(DEBUG_RACE) - printk("done returned (DID_OK: Status=%x; Message=%x).\n", - CURRENT_SC->SCp.Status, CURRENT_SC->SCp.Message); + printk("done returned (DID_OK: Status=%x; Message=%x).\n", + CURRENT_SC->SCp.Status, CURRENT_SC->SCp.Message); #endif - return; - } + return; + } if(CURRENT_SC) - CURRENT_SC->SCp.phase |= 1<<16 ; + CURRENT_SC->SCp.phase |= 1<<16; SETPORT(SIMODE0, 0); SETPORT(SIMODE1, ENPHASEMIS|ENBUSFREE); @@ -2490,7 +2585,7 @@ #ifdef SKIP_PORTS if(HOSTDATA(shpnt)->debug & debug_skipports) - return; + return; #endif printk("\n%s: ", CURRENT_SC ? "on bus" : "waiting"); @@ -2509,30 +2604,29 @@ printk(" SCSISIG ("); s=GETPORT(SCSISIG); - switch(s & P_MASK) - { - case P_DATAO: - printk("DATA OUT"); - break; - case P_DATAI: - printk("DATA IN"); - break; - case P_CMD: - printk("COMMAND"); - break; - case P_STATUS: - printk("STATUS"); - break; - case P_MSGO: - printk("MESSAGE OUT"); - break; - case P_MSGI: - printk("MESSAGE IN"); - break; - default: - printk("*illegal*"); - break; - } + switch(s & P_MASK) { + case P_DATAO: + printk("DATA OUT"); + break; + case P_DATAI: + printk("DATA IN"); + break; + case P_CMD: + printk("COMMAND"); + break; + case P_STATUS: + printk("STATUS"); + break; + case P_MSGO: + printk("MESSAGE OUT"); + break; + case P_MSGI: + printk("MESSAGE IN"); + break; + default: + printk("*illegal*"); + break; + } printk("); "); @@ -2638,19 +2732,6 @@ if(s & SWINT) printk("SWINT "); printk("); "); - -#if 0 - printk("DMACNTRL1 ("); - - s=GETPORT(DMACNTRL1); - if(s & PWRDWN) printk("PWRDN "); - printk("); "); - - - printk("STK (%d); ", s & 0xf); - -#endif - printk("DMASTAT ("); s=GETPORT(DMASTAT); if(s & ATDONE) printk("ATDONE "); @@ -2707,11 +2788,10 @@ save_flags(flags); cli(); printk("aha152x: entering %s() (%x)\n", func, jiffies); - if(in_driver) - { - printk("%s should leave first.\n", should_leave); - panic("aha152x: already in driver\n"); - } + if(in_driver) { + printk("%s should leave first.\n", should_leave); + panic("aha152x: already in driver\n"); + } in_driver++; should_leave=func; @@ -2725,11 +2805,10 @@ save_flags(flags); cli(); printk("\naha152x: leaving %s() (%x)\n", func, jiffies); - if(!in_driver) - { - printk("aha152x: %s already left.\n", should_leave); - panic("aha152x: %s already left driver.\n"); - } + if(!in_driver) { + printk("aha152x: %s already left.\n", should_leave); + panic("aha152x: %s already left driver.\n"); + } in_driver--; should_leave=func; @@ -2743,49 +2822,47 @@ static void show_command(Scsi_Cmnd *ptr) { printk("0x%08x: target=%d; lun=%d; cmnd=(", - (unsigned int) ptr, ptr->target, ptr->lun); + (unsigned int) ptr, ptr->target, ptr->lun); print_command(ptr->cmnd); printk("); residual=%d; buffers=%d; phase |", - ptr->SCp.this_residual, ptr->SCp.buffers_residual); + ptr->SCp.this_residual, ptr->SCp.buffers_residual); if(ptr->SCp.phase & not_issued ) printk("not issued|"); if(ptr->SCp.phase & in_selection) printk("in selection|"); if(ptr->SCp.phase & disconnected) printk("disconnected|"); if(ptr->SCp.phase & aborted ) printk("aborted|"); if(ptr->SCp.phase & sent_ident ) printk("send_ident|"); - if(ptr->SCp.phase & in_other) - { - printk("; in other("); - switch((ptr->SCp.phase >> 16) & P_MASK) - { - case P_DATAO: - printk("DATA OUT"); - break; - case P_DATAI: - printk("DATA IN"); - break; - case P_CMD: - printk("COMMAND"); - break; - case P_STATUS: - printk("STATUS"); - break; - case P_MSGO: - printk("MESSAGE OUT"); - break; - case P_MSGI: - printk("MESSAGE IN"); - break; - default: - printk("*illegal*"); - break; - } - printk(")"); - if(ptr->SCp.phase & (1<<16)) - printk("; phaseend"); + if(ptr->SCp.phase & in_other) { + printk("; in other("); + switch((ptr->SCp.phase >> 16) & P_MASK) { + case P_DATAO: + printk("DATA OUT"); + break; + case P_DATAI: + printk("DATA IN"); + break; + case P_CMD: + printk("COMMAND"); + break; + case P_STATUS: + printk("STATUS"); + break; + case P_MSGO: + printk("MESSAGE OUT"); + break; + case P_MSGI: + printk("MESSAGE IN"); + break; + default: + printk("*illegal*"); + break; } + printk(")"); + if(ptr->SCp.phase & (1<<16)) + printk("; phaseend"); + } printk("; next=0x%08x\n", (unsigned int) ptr->host_scribble); } @@ -2845,57 +2922,234 @@ if(ptr->SCp.phase & disconnected) SPRINTF("disconnected|"); if(ptr->SCp.phase & aborted ) SPRINTF("aborted|"); if(ptr->SCp.phase & sent_ident ) SPRINTF("send_ident|"); - if(ptr->SCp.phase & in_other) - { - SPRINTF("; in other("); - switch((ptr->SCp.phase >> 16) & P_MASK) - { - case P_DATAO: - SPRINTF("DATA OUT"); - break; - case P_DATAI: - SPRINTF("DATA IN"); - break; - case P_CMD: - SPRINTF("COMMAND"); - break; - case P_STATUS: - SPRINTF("STATUS"); - break; - case P_MSGO: - SPRINTF("MESSAGE OUT"); - break; - case P_MSGI: - SPRINTF("MESSAGE IN"); - break; - default: - SPRINTF("*illegal*"); - break; - } - SPRINTF(")"); - if(ptr->SCp.phase & (1<<16)) - SPRINTF("; phaseend"); + if(ptr->SCp.phase & in_other) { + SPRINTF("; in other("); + switch((ptr->SCp.phase >> 16) & P_MASK) { + case P_DATAO: + SPRINTF("DATA OUT"); + break; + case P_DATAI: + SPRINTF("DATA IN"); + break; + case P_CMD: + SPRINTF("COMMAND"); + break; + case P_STATUS: + SPRINTF("STATUS"); + break; + case P_MSGO: + SPRINTF("MESSAGE OUT"); + break; + case P_MSGI: + SPRINTF("MESSAGE IN"); + break; + default: + SPRINTF("*illegal*"); + break; } + SPRINTF(")"); + if(ptr->SCp.phase & (1<<16)) + SPRINTF("; phaseend"); + } SPRINTF("; next=0x%08x\n", (unsigned int) ptr->host_scribble); return(pos-start); } +static int get_ports(struct Scsi_Host *shpnt, char *pos) +{ + char *start = pos; + int s; + +#ifdef SKIP_PORTS + if(HOSTDATA(shpnt)->debug & debug_skipports) + return; +#endif + + SPRINTF("\n%s: ", CURRENT_SC ? "on bus" : "waiting"); + + s=GETPORT(SCSISEQ); + SPRINTF("SCSISEQ ("); + if(s & TEMODEO) SPRINTF("TARGET MODE "); + if(s & ENSELO) SPRINTF("SELO "); + if(s & ENSELI) SPRINTF("SELI "); + if(s & ENRESELI) SPRINTF("RESELI "); + if(s & ENAUTOATNO) SPRINTF("AUTOATNO "); + if(s & ENAUTOATNI) SPRINTF("AUTOATNI "); + if(s & ENAUTOATNP) SPRINTF("AUTOATNP "); + if(s & SCSIRSTO) SPRINTF("SCSIRSTO "); + SPRINTF(");"); + + SPRINTF(" SCSISIG ("); + s=GETPORT(SCSISIG); + switch(s & P_MASK) { + case P_DATAO: + SPRINTF("DATA OUT"); + break; + case P_DATAI: + SPRINTF("DATA IN"); + break; + case P_CMD: + SPRINTF("COMMAND"); + break; + case P_STATUS: + SPRINTF("STATUS"); + break; + case P_MSGO: + SPRINTF("MESSAGE OUT"); + break; + case P_MSGI: + SPRINTF("MESSAGE IN"); + break; + default: + SPRINTF("*illegal*"); + break; + } + + SPRINTF("); "); + + SPRINTF("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo"); + + SPRINTF("SSTAT ("); + s=GETPORT(SSTAT0); + if(s & TARGET) SPRINTF("TARGET "); + if(s & SELDO) SPRINTF("SELDO "); + if(s & SELDI) SPRINTF("SELDI "); + if(s & SELINGO) SPRINTF("SELINGO "); + if(s & SWRAP) SPRINTF("SWRAP "); + if(s & SDONE) SPRINTF("SDONE "); + if(s & SPIORDY) SPRINTF("SPIORDY "); + if(s & DMADONE) SPRINTF("DMADONE "); + + s=GETPORT(SSTAT1); + if(s & SELTO) SPRINTF("SELTO "); + if(s & ATNTARG) SPRINTF("ATNTARG "); + if(s & SCSIRSTI) SPRINTF("SCSIRSTI "); + if(s & PHASEMIS) SPRINTF("PHASEMIS "); + if(s & BUSFREE) SPRINTF("BUSFREE "); + if(s & SCSIPERR) SPRINTF("SCSIPERR "); + if(s & PHASECHG) SPRINTF("PHASECHG "); + if(s & REQINIT) SPRINTF("REQINIT "); + SPRINTF("); "); + + + SPRINTF("SSTAT ("); + + s=GETPORT(SSTAT0) & GETPORT(SIMODE0); + + if(s & TARGET) SPRINTF("TARGET "); + if(s & SELDO) SPRINTF("SELDO "); + if(s & SELDI) SPRINTF("SELDI "); + if(s & SELINGO) SPRINTF("SELINGO "); + if(s & SWRAP) SPRINTF("SWRAP "); + if(s & SDONE) SPRINTF("SDONE "); + if(s & SPIORDY) SPRINTF("SPIORDY "); + if(s & DMADONE) SPRINTF("DMADONE "); + + s=GETPORT(SSTAT1) & GETPORT(SIMODE1); + + if(s & SELTO) SPRINTF("SELTO "); + if(s & ATNTARG) SPRINTF("ATNTARG "); + if(s & SCSIRSTI) SPRINTF("SCSIRSTI "); + if(s & PHASEMIS) SPRINTF("PHASEMIS "); + if(s & BUSFREE) SPRINTF("BUSFREE "); + if(s & SCSIPERR) SPRINTF("SCSIPERR "); + if(s & PHASECHG) SPRINTF("PHASECHG "); + if(s & REQINIT) SPRINTF("REQINIT "); + SPRINTF("); "); + + SPRINTF("SXFRCTL0 ("); + + s=GETPORT(SXFRCTL0); + if(s & SCSIEN) SPRINTF("SCSIEN "); + if(s & DMAEN) SPRINTF("DMAEN "); + if(s & CH1) SPRINTF("CH1 "); + if(s & CLRSTCNT) SPRINTF("CLRSTCNT "); + if(s & SPIOEN) SPRINTF("SPIOEN "); + if(s & CLRCH1) SPRINTF("CLRCH1 "); + SPRINTF("); "); + + SPRINTF("SIGNAL ("); + + s=GETPORT(SCSISIG); + if(s & ATNI) SPRINTF("ATNI "); + if(s & SELI) SPRINTF("SELI "); + if(s & BSYI) SPRINTF("BSYI "); + if(s & REQI) SPRINTF("REQI "); + if(s & ACKI) SPRINTF("ACKI "); + SPRINTF("); "); + + SPRINTF("SELID (%02x), ", GETPORT(SELID)); + + SPRINTF("SSTAT2 ("); + + s=GETPORT(SSTAT2); + if(s & SOFFSET) SPRINTF("SOFFSET "); + if(s & SEMPTY) SPRINTF("SEMPTY "); + if(s & SFULL) SPRINTF("SFULL "); + SPRINTF("); SFCNT (%d); ", s & (SFULL|SFCNT)); + + s=GETPORT(SSTAT3); + SPRINTF("SCSICNT (%d), OFFCNT(%d), ", (s&0xf0)>>4, s&0x0f); + + SPRINTF("SSTAT4 ("); + s=GETPORT(SSTAT4); + if(s & SYNCERR) SPRINTF("SYNCERR "); + if(s & FWERR) SPRINTF("FWERR "); + if(s & FRERR) SPRINTF("FRERR "); + SPRINTF("); "); + + SPRINTF("DMACNTRL0 ("); + s=GETPORT(DMACNTRL0); + SPRINTF("%s ", s & _8BIT ? "8BIT" : "16BIT"); + SPRINTF("%s ", s & DMA ? "DMA" : "PIO" ); + SPRINTF("%s ", s & WRITE_READ ? "WRITE" : "READ" ); + if(s & ENDMA) SPRINTF("ENDMA "); + if(s & INTEN) SPRINTF("INTEN "); + if(s & RSTFIFO) SPRINTF("RSTFIFO "); + if(s & SWINT) SPRINTF("SWINT "); + SPRINTF("); "); + + SPRINTF("DMASTAT ("); + s=GETPORT(DMASTAT); + if(s & ATDONE) SPRINTF("ATDONE "); + if(s & WORDRDY) SPRINTF("WORDRDY "); + if(s & DFIFOFULL) SPRINTF("DFIFOFULL "); + if(s & DFIFOEMP) SPRINTF("DFIFOEMP "); + SPRINTF(")\n\n"); + + SPRINTF("enabled interrupts ("); + + s=GETPORT(SIMODE0); + if(s & ENSELDO) SPRINTF("ENSELDO "); + if(s & ENSELDI) SPRINTF("ENSELDI "); + if(s & ENSELINGO) SPRINTF("ENSELINGO "); + if(s & ENSWRAP) SPRINTF("ENSWRAP "); + if(s & ENSDONE) SPRINTF("ENSDONE "); + if(s & ENSPIORDY) SPRINTF("ENSPIORDY "); + if(s & ENDMADONE) SPRINTF("ENDMADONE "); + + s=GETPORT(SIMODE1); + if(s & ENSELTIMO) SPRINTF("ENSELTIMO "); + if(s & ENATNTARG) SPRINTF("ENATNTARG "); + if(s & ENPHASEMIS) SPRINTF("ENPHASEMIS "); + if(s & ENBUSFREE) SPRINTF("ENBUSFREE "); + if(s & ENSCSIPERR) SPRINTF("ENSCSIPERR "); + if(s & ENPHASECHG) SPRINTF("ENPHASECHG "); + if(s & ENREQINIT) SPRINTF("ENREQINIT "); + SPRINTF(")\n"); + + return (pos-start); +} + #undef SPRINTF #define SPRINTF(args...) do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0) -int aha152x_proc_info( - char *buffer, - char **start, - off_t offset, - int length, - int hostno, - int inout - ) +int aha152x_proc_info(char *buffer, char **start, + off_t offset, int length, int hostno, int inout) { int i; char *pos = buffer; - Scsi_Device *scd; struct Scsi_Host *shpnt; unsigned long flags; Scsi_Cmnd *ptr; @@ -2915,7 +3169,7 @@ save_flags(flags); cli(); - SPRINTF("vital data:\nioports 0x%04x to 0x%04x\n", + SPRINTF("ioports 0x%04x to 0x%04x\n", shpnt->io_port, shpnt->io_port+shpnt->n_io_port-1); SPRINTF("interrupt 0x%02x\n", shpnt->irq); SPRINTF("disconnection/reconnection %s\n", @@ -2924,35 +3178,36 @@ HOSTDATA(shpnt)->parity ? "enabled" : "disabled"); SPRINTF("synchronous transfers %s\n", HOSTDATA(shpnt)->synchronous ? "enabled" : "disabled"); - SPRINTF("current queued %d commands\n", - HOSTDATA(shpnt)->commands); + SPRINTF("%d commands currently queued\n", HOSTDATA(shpnt)->commands); + if(HOSTDATA(shpnt)->synchronous) { #if 0 - SPRINTF("synchronously operating targets (tick=%ld ns):\n", - 250000000/loops_per_sec); - for(i=0; i<8; i++) - if(HOSTDATA(shpnt)->syncrate[i]&0x7f) - SPRINTF("target %d: period %dT/%ldns; req/ack offset %d\n", - i, - (((HOSTDATA(shpnt)->syncrate[i]&0x70)>>4)+2), - (((HOSTDATA(shpnt)->syncrate[i]&0x70)>>4)+2)* - 250000000/loops_per_sec, - HOSTDATA(shpnt)->syncrate[i]&0x0f); + SPRINTF("synchronously operating targets (tick=%ld ns):\n", + 250000000/loops_per_sec); + for(i=0; i<8; i++) + if(HOSTDATA(shpnt)->syncrate[i]&0x7f) + SPRINTF("target %d: period %dT/%ldns; req/ack offset %d\n", + i, + (((HOSTDATA(shpnt)->syncrate[i]&0x70)>>4)+2), + (((HOSTDATA(shpnt)->syncrate[i]&0x70)>>4)+2)* + 250000000/loops_per_sec, + HOSTDATA(shpnt)->syncrate[i]&0x0f); #else - SPRINTF("synchronously operating targets (tick=50 ns):\n"); - for(i=0; i<8; i++) - if(HOSTDATA(shpnt)->syncrate[i]&0x7f) - SPRINTF("target %d: period %dT/%dns; req/ack offset %d\n", - i, - (((HOSTDATA(shpnt)->syncrate[i]&0x70)>>4)+2), - (((HOSTDATA(shpnt)->syncrate[i]&0x70)>>4)+2)*50, - HOSTDATA(shpnt)->syncrate[i]&0x0f); + SPRINTF("synchronously operating targets (tick=50 ns):\n"); + for(i=0; i<8; i++) + if(HOSTDATA(shpnt)->syncrate[i]&0x7f) + SPRINTF("target %d: period %dT/%dns; req/ack offset %d\n", + i, + (((HOSTDATA(shpnt)->syncrate[i]&0x70)>>4)+2), + (((HOSTDATA(shpnt)->syncrate[i]&0x70)>>4)+2)*50, + HOSTDATA(shpnt)->syncrate[i]&0x0f); #endif + } #ifdef DEBUG_AHA152X #define PDEBUG(flags,txt) if(HOSTDATA(shpnt)->debug & flags) SPRINTF("(%s) ", txt); - SPRINTF("enabled debugging options:\n"); + SPRINTF("enabled debugging options: "); PDEBUG(debug_skipports, "skip ports"); PDEBUG(debug_queue, "queue"); @@ -2974,64 +3229,30 @@ SPRINTF("\n"); #endif - SPRINTF("queue status:\nnot yet issued commands:\n"); - for(ptr=ISSUE_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) - pos += get_command(pos, ptr); - - if(CURRENT_SC) - { - SPRINTF("current command:\n"); - pos += get_command(pos, CURRENT_SC); - } - - SPRINTF("disconnected commands:\n"); - for(ptr=DISCONNECTED_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) - pos += get_command(pos, ptr); + SPRINTF("\nqueue status:\n"); + if(ISSUE_SC) { + SPRINTF("not yet issued commands:\n"); + for(ptr=ISSUE_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) + pos += get_command(pos, ptr); + } else + SPRINTF("no not yet issued commands\n"); + + if(CURRENT_SC) { + SPRINTF("current command:\n"); + pos += get_command(pos, CURRENT_SC); + } else + SPRINTF("no current command\n"); + + if(DISCONNECTED_SC) { + SPRINTF("disconnected commands:\n"); + for(ptr=DISCONNECTED_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) + pos += get_command(pos, ptr); + } else + SPRINTF("no disconnected commands\n"); restore_flags(flags); - - scd = scsi_devices; - - SPRINTF("Attached devices: %s\n", (scd)?"":"none"); - - while (scd) { - if (scd->host == shpnt) { - - SPRINTF("Channel: %02d Id: %02d Lun: %02d\n Vendor: ", - scd->channel, scd->id, scd->lun); - for (i=0; i<8; i++) { - if (scd->vendor[i] >= 0x20) - SPRINTF("%c", scd->vendor[i]); - else - SPRINTF(" "); - } - SPRINTF(" Model: "); - for (i = 0; i < 16; i++) { - if (scd->model[i] >= 0x20) - SPRINTF("%c", scd->model[i]); - else - SPRINTF(" "); - } - SPRINTF(" Rev: "); - for (i = 0; i < 4; i++) { - if (scd->rev[i] >= 0x20) - SPRINTF("%c", scd->rev[i]); - else - SPRINTF(" "); - } - SPRINTF("\n"); - - SPRINTF(" Type: %d ", scd->type); - SPRINTF(" ANSI SCSI revision: %02x", - (scd->scsi_level < 3)?1:2); - - if (scd->scsi_level == 2) - SPRINTF(" CCS\n"); - else - SPRINTF("\n"); - } - scd = scd->next; - } + + pos += get_ports(shpnt, pos); *start=buffer+offset; if (pos - buffer < offset) diff -ur --new-file old/linux/drivers/scsi/aha152x.h new/linux/drivers/scsi/aha152x.h --- old/linux/drivers/scsi/aha152x.h Sun Jun 9 11:48:07 1996 +++ new/linux/drivers/scsi/aha152x.h Sat Aug 17 20:02:50 1996 @@ -2,7 +2,7 @@ #define _AHA152X_H /* - * $Id: aha152x.h,v 1.16 1996/06/09 00:08:30 fischer Exp $ + * $Id: aha152x.h,v 1.17 1996/08/17 16:07:38 fischer Exp fischer $ */ #if defined(__KERNEL__) @@ -11,362 +11,346 @@ #include "scsi.h" #include -int aha152x_detect(Scsi_Host_Template *); -int aha152x_command(Scsi_Cmnd *); -int aha152x_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); -int aha152x_abort(Scsi_Cmnd *); -int aha152x_reset(Scsi_Cmnd *); -int aha152x_biosparam(Disk *, kdev_t, int*); +int aha152x_detect(Scsi_Host_Template *); +int aha152x_command(Scsi_Cmnd *); +int aha152x_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +int aha152x_abort(Scsi_Cmnd *); +int aha152x_reset(Scsi_Cmnd *, unsigned int); +int aha152x_biosparam(Disk *, kdev_t, int*); int aha152x_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout); /* number of queueable commands (unless we support more than 1 cmd_per_lun this should do) */ -#define AHA152X_MAXQUEUE 7 +#define AHA152X_MAXQUEUE 7 -#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 1.16 $" +#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 1.17 $" extern struct proc_dir_entry proc_scsi_aha152x; /* Initial value of Scsi_Host entry */ -#define AHA152X { /* next */ NULL, \ - /* usage_count */ NULL, \ - /* proc_dir */ &proc_scsi_aha152x, \ - /* proc_info */ aha152x_proc_info, \ - /* name */ AHA152X_REVID, \ - /* detect */ aha152x_detect, \ - /* release */ NULL, \ - /* info */ NULL, \ - /* command */ aha152x_command, \ - /* queuecommand */ aha152x_queue, \ - /* abort */ aha152x_abort, \ - /* reset */ aha152x_reset, \ - /* slave_attach */ /* NULL */ 0, \ - /* bios_param */ aha152x_biosparam, \ - /* can_queue */ 1, \ - /* this_id */ 7, \ - /* sg_tablesize */ SG_ALL, \ - /* cmd_per_lun */ 1, \ - /* present */ 0, \ - /* unchecked_isa_dma */ 0, \ - /* use_clustering */ DISABLE_CLUSTERING } +#define AHA152X { /* next */ 0, \ + /* usage_count */ 0, \ + /* proc_dir */ &proc_scsi_aha152x, \ + /* proc_info */ aha152x_proc_info, \ + /* name */ AHA152X_REVID, \ + /* detect */ aha152x_detect, \ + /* release */ 0, \ + /* info */ 0, \ + /* command */ aha152x_command, \ + /* queuecommand */ aha152x_queue, \ + /* abort */ aha152x_abort, \ + /* reset */ aha152x_reset, \ + /* slave_attach */ 0, \ + /* bios_param */ aha152x_biosparam, \ + /* can_queue */ 1, \ + /* this_id */ 7, \ + /* sg_tablesize */ SG_ALL, \ + /* cmd_per_lun */ 1, \ + /* present */ 0, \ + /* unchecked_isa_dma */ 0, \ + /* use_clustering */ DISABLE_CLUSTERING } #endif /* port addresses */ -#define SCSISEQ (shpnt->io_port+0x00) /* SCSI sequence control */ -#define SXFRCTL0 (shpnt->io_port+0x01) /* SCSI transfer control 0 */ -#define SXFRCTL1 (shpnt->io_port+0x02) /* SCSI transfer control 1 */ -#define SCSISIG (shpnt->io_port+0x03) /* SCSI signal in/out */ -#define SCSIRATE (shpnt->io_port+0x04) /* SCSI rate control */ -#define SELID (shpnt->io_port+0x05) /* selection/reselection ID */ -#define SCSIID SELID /* SCSI ID */ -#define SCSIDAT (shpnt->io_port+0x06) /* SCSI latched data */ -#define SCSIBUS (shpnt->io_port+0x07) /* SCSI data bus */ -#define STCNT0 (shpnt->io_port+0x08) /* SCSI transfer count 0 */ -#define STCNT1 (shpnt->io_port+0x09) /* SCSI transfer count 1 */ -#define STCNT2 (shpnt->io_port+0x0a) /* SCSI transfer count 2 */ -#define SSTAT0 (shpnt->io_port+0x0b) /* SCSI interrupt status 0 */ -#define SSTAT1 (shpnt->io_port+0x0c) /* SCSI interrupt status 1 */ -#define SSTAT2 (shpnt->io_port+0x0d) /* SCSI interrupt status 2 */ -#define SCSITEST (shpnt->io_port+0x0e) /* SCSI test control */ -#define SSTAT3 SCSITEST /* SCSI interrupt status 3 */ -#define SSTAT4 (shpnt->io_port+0x0f) /* SCSI status 4 */ -#define SIMODE0 (shpnt->io_port+0x10) /* SCSI interrupt mode 0 */ -#define SIMODE1 (shpnt->io_port+0x11) /* SCSI interrupt mode 1 */ -#define DMACNTRL0 (shpnt->io_port+0x12) /* DMA control 0 */ -#define DMACNTRL1 (shpnt->io_port+0x13) /* DMA control 1 */ -#define DMASTAT (shpnt->io_port+0x14) /* DMA status */ -#define FIFOSTAT (shpnt->io_port+0x15) /* FIFO status */ -#define DATAPORT (shpnt->io_port+0x16) /* DATA port */ -#define BRSTCNTRL (shpnt->io_port+0x18) /* burst control */ -#define PORTA (shpnt->io_port+0x1a) /* PORT A */ -#define PORTB (shpnt->io_port+0x1b) /* PORT B */ -#define REV (shpnt->io_port+0x1c) /* revision */ -#define STACK (shpnt->io_port+0x1d) /* stack */ -#define TEST (shpnt->io_port+0x1e) /* test register */ +#define SCSISEQ (shpnt->io_port+0x00) /* SCSI sequence control */ +#define SXFRCTL0 (shpnt->io_port+0x01) /* SCSI transfer control 0 */ +#define SXFRCTL1 (shpnt->io_port+0x02) /* SCSI transfer control 1 */ +#define SCSISIG (shpnt->io_port+0x03) /* SCSI signal in/out */ +#define SCSIRATE (shpnt->io_port+0x04) /* SCSI rate control */ +#define SELID (shpnt->io_port+0x05) /* selection/reselection ID */ +#define SCSIID SELID /* SCSI ID */ +#define SCSIDAT (shpnt->io_port+0x06) /* SCSI latched data */ +#define SCSIBUS (shpnt->io_port+0x07) /* SCSI data bus */ +#define STCNT0 (shpnt->io_port+0x08) /* SCSI transfer count 0 */ +#define STCNT1 (shpnt->io_port+0x09) /* SCSI transfer count 1 */ +#define STCNT2 (shpnt->io_port+0x0a) /* SCSI transfer count 2 */ +#define SSTAT0 (shpnt->io_port+0x0b) /* SCSI interrupt status 0 */ +#define SSTAT1 (shpnt->io_port+0x0c) /* SCSI interrupt status 1 */ +#define SSTAT2 (shpnt->io_port+0x0d) /* SCSI interrupt status 2 */ +#define SCSITEST (shpnt->io_port+0x0e) /* SCSI test control */ +#define SSTAT3 SCSITEST /* SCSI interrupt status 3 */ +#define SSTAT4 (shpnt->io_port+0x0f) /* SCSI status 4 */ +#define SIMODE0 (shpnt->io_port+0x10) /* SCSI interrupt mode 0 */ +#define SIMODE1 (shpnt->io_port+0x11) /* SCSI interrupt mode 1 */ +#define DMACNTRL0 (shpnt->io_port+0x12) /* DMA control 0 */ +#define DMACNTRL1 (shpnt->io_port+0x13) /* DMA control 1 */ +#define DMASTAT (shpnt->io_port+0x14) /* DMA status */ +#define FIFOSTAT (shpnt->io_port+0x15) /* FIFO status */ +#define DATAPORT (shpnt->io_port+0x16) /* DATA port */ +#define BRSTCNTRL (shpnt->io_port+0x18) /* burst control */ +#define PORTA (shpnt->io_port+0x1a) /* PORT A */ +#define PORTB (shpnt->io_port+0x1b) /* PORT B */ +#define REV (shpnt->io_port+0x1c) /* revision */ +#define STACK (shpnt->io_port+0x1d) /* stack */ +#define TEST (shpnt->io_port+0x1e) /* test register */ /* used in aha152x_porttest */ -#define O_PORTA (0x1a) /* PORT A */ -#define O_PORTB (0x1b) /* PORT B */ -#define O_DMACNTRL1 (0x13) /* DMA control 1 */ -#define O_STACK (0x1d) /* stack */ -#define IO_RANGE 0x20 +#define O_PORTA 0x1a /* PORT A */ +#define O_PORTB 0x1b /* PORT B */ +#define O_DMACNTRL1 0x13 /* DMA control 1 */ +#define O_STACK 0x1d /* stack */ +#define IO_RANGE 0x20 /* bits and bitmasks to ports */ /* SCSI sequence control */ -#define TEMODEO 0x80 -#define ENSELO 0x40 -#define ENSELI 0x20 -#define ENRESELI 0x10 -#define ENAUTOATNO 0x08 -#define ENAUTOATNI 0x04 -#define ENAUTOATNP 0x02 -#define SCSIRSTO 0x01 +#define TEMODEO 0x80 +#define ENSELO 0x40 +#define ENSELI 0x20 +#define ENRESELI 0x10 +#define ENAUTOATNO 0x08 +#define ENAUTOATNI 0x04 +#define ENAUTOATNP 0x02 +#define SCSIRSTO 0x01 /* SCSI transfer control 0 */ -#define SCSIEN 0x80 -#define DMAEN 0x40 -#define CH1 0x20 -#define CLRSTCNT 0x10 -#define SPIOEN 0x08 -#define CLRCH1 0x02 +#define SCSIEN 0x80 +#define DMAEN 0x40 +#define CH1 0x20 +#define CLRSTCNT 0x10 +#define SPIOEN 0x08 +#define CLRCH1 0x02 /* SCSI transfer control 1 */ -#define BITBUCKET 0x80 -#define SWRAPEN 0x40 -#define ENSPCHK 0x20 -#define STIMESEL 0x18 /* mask */ -#define STIMESEL_ 3 -#define ENSTIMER 0x04 -#define BYTEALIGN 0x02 +#define BITBUCKET 0x80 +#define SWRAPEN 0x40 +#define ENSPCHK 0x20 +#define STIMESEL 0x18 /* mask */ +#define STIMESEL_ 3 +#define ENSTIMER 0x04 +#define BYTEALIGN 0x02 /* SCSI signal IN */ -#define CDI 0x80 -#define IOI 0x40 -#define MSGI 0x20 -#define ATNI 0x10 -#define SELI 0x08 -#define BSYI 0x04 -#define REQI 0x02 -#define ACKI 0x01 +#define CDI 0x80 +#define IOI 0x40 +#define MSGI 0x20 +#define ATNI 0x10 +#define SELI 0x08 +#define BSYI 0x04 +#define REQI 0x02 +#define ACKI 0x01 /* SCSI Phases */ -#define P_MASK (MSGI|CDI|IOI) -#define P_DATAO (0) -#define P_DATAI (IOI) -#define P_CMD (CDI) -#define P_STATUS (CDI|IOI) -#define P_MSGO (MSGI|CDI) -#define P_MSGI (MSGI|CDI|IOI) +#define P_MASK (MSGI|CDI|IOI) +#define P_DATAO (0) +#define P_DATAI (IOI) +#define P_CMD (CDI) +#define P_STATUS (CDI|IOI) +#define P_MSGO (MSGI|CDI) +#define P_MSGI (MSGI|CDI|IOI) /* SCSI signal OUT */ -#define CDO 0x80 -#define IOO 0x40 -#define MSGO 0x20 -#define ATNO 0x10 -#define SELO 0x08 -#define BSYO 0x04 -#define REQO 0x02 -#define ACKO 0x01 +#define CDO 0x80 +#define IOO 0x40 +#define MSGO 0x20 +#define ATNO 0x10 +#define SELO 0x08 +#define BSYO 0x04 +#define REQO 0x02 +#define ACKO 0x01 /* SCSI rate control */ -#define SXFR 0x70 /* mask */ -#define SXFR_ 4 -#define SOFS 0x0f /* mask */ +#define SXFR 0x70 /* mask */ +#define SXFR_ 4 +#define SOFS 0x0f /* mask */ /* SCSI ID */ -#define OID 0x70 -#define OID_ 4 -#define TID 0x07 +#define OID 0x70 +#define OID_ 4 +#define TID 0x07 /* SCSI transfer count */ -#define GETSTCNT() ( (GETPORT(STCNT2)<<16) \ - + (GETPORT(STCNT1)<< 8) \ - + GETPORT(STCNT0) ) - -#define SETSTCNT(X) { SETPORT(STCNT2, ((X) & 0xFF0000) >> 16); \ - SETPORT(STCNT1, ((X) & 0x00FF00) >> 8); \ - SETPORT(STCNT0, ((X) & 0x0000FF) ); } +#define GETSTCNT() ( (GETPORT(STCNT2)<<16) \ + + (GETPORT(STCNT1)<< 8) \ + + GETPORT(STCNT0) ) + +#define SETSTCNT(X) { SETPORT(STCNT2, ((X) & 0xFF0000) >> 16); \ + SETPORT(STCNT1, ((X) & 0x00FF00) >> 8); \ + SETPORT(STCNT0, ((X) & 0x0000FF) ); } /* SCSI interrupt status */ -#define TARGET 0x80 -#define SELDO 0x40 -#define SELDI 0x20 -#define SELINGO 0x10 -#define SWRAP 0x08 -#define SDONE 0x04 -#define SPIORDY 0x02 -#define DMADONE 0x01 - -#define SETSDONE 0x80 -#define CLRSELDO 0x40 -#define CLRSELDI 0x20 -#define CLRSELINGO 0x10 -#define CLRSWRAP 0x08 -#define CLRSDONE 0x04 -#define CLRSPIORDY 0x02 -#define CLRDMADONE 0x01 +#define TARGET 0x80 +#define SELDO 0x40 +#define SELDI 0x20 +#define SELINGO 0x10 +#define SWRAP 0x08 +#define SDONE 0x04 +#define SPIORDY 0x02 +#define DMADONE 0x01 + +#define SETSDONE 0x80 +#define CLRSELDO 0x40 +#define CLRSELDI 0x20 +#define CLRSELINGO 0x10 +#define CLRSWRAP 0x08 +#define CLRSDONE 0x04 +#define CLRSPIORDY 0x02 +#define CLRDMADONE 0x01 /* SCSI status 1 */ -#define SELTO 0x80 -#define ATNTARG 0x40 -#define SCSIRSTI 0x20 -#define PHASEMIS 0x10 -#define BUSFREE 0x08 -#define SCSIPERR 0x04 -#define PHASECHG 0x02 -#define REQINIT 0x01 - -#define CLRSELTIMO 0x80 -#define CLRATNO 0x40 -#define CLRSCSIRSTI 0x20 -#define CLRBUSFREE 0x08 -#define CLRSCSIPERR 0x04 -#define CLRPHASECHG 0x02 -#define CLRREQINIT 0x01 +#define SELTO 0x80 +#define ATNTARG 0x40 +#define SCSIRSTI 0x20 +#define PHASEMIS 0x10 +#define BUSFREE 0x08 +#define SCSIPERR 0x04 +#define PHASECHG 0x02 +#define REQINIT 0x01 + +#define CLRSELTIMO 0x80 +#define CLRATNO 0x40 +#define CLRSCSIRSTI 0x20 +#define CLRBUSFREE 0x08 +#define CLRSCSIPERR 0x04 +#define CLRPHASECHG 0x02 +#define CLRREQINIT 0x01 /* SCSI status 2 */ -#define SOFFSET 0x20 -#define SEMPTY 0x10 -#define SFULL 0x08 -#define SFCNT 0x07 /* mask */ +#define SOFFSET 0x20 +#define SEMPTY 0x10 +#define SFULL 0x08 +#define SFCNT 0x07 /* mask */ /* SCSI status 3 */ -#define SCSICNT 0xf0 /* mask */ -#define SCSICNT_ 4 -#define OFFCNT 0x0f /* mask */ +#define SCSICNT 0xf0 /* mask */ +#define SCSICNT_ 4 +#define OFFCNT 0x0f /* mask */ /* SCSI TEST control */ -#define SCTESTU 0x08 -#define SCTESTD 0x04 -#define STCTEST 0x01 +#define SCTESTU 0x08 +#define SCTESTD 0x04 +#define STCTEST 0x01 /* SCSI status 4 */ -#define SYNCERR 0x04 -#define FWERR 0x02 -#define FRERR 0x01 - -#define CLRSYNCERR 0x04 -#define CLRFWERR 0x02 -#define CLRFRERR 0x01 +#define SYNCERR 0x04 +#define FWERR 0x02 +#define FRERR 0x01 + +#define CLRSYNCERR 0x04 +#define CLRFWERR 0x02 +#define CLRFRERR 0x01 /* SCSI interrupt mode 0 */ -#define ENSELDO 0x40 -#define ENSELDI 0x20 -#define ENSELINGO 0x10 -#define ENSWRAP 0x08 -#define ENSDONE 0x04 -#define ENSPIORDY 0x02 -#define ENDMADONE 0x01 +#define ENSELDO 0x40 +#define ENSELDI 0x20 +#define ENSELINGO 0x10 +#define ENSWRAP 0x08 +#define ENSDONE 0x04 +#define ENSPIORDY 0x02 +#define ENDMADONE 0x01 /* SCSI interrupt mode 1 */ -#define ENSELTIMO 0x80 -#define ENATNTARG 0x40 -#define ENSCSIRST 0x20 -#define ENPHASEMIS 0x10 -#define ENBUSFREE 0x08 -#define ENSCSIPERR 0x04 -#define ENPHASECHG 0x02 -#define ENREQINIT 0x01 +#define ENSELTIMO 0x80 +#define ENATNTARG 0x40 +#define ENSCSIRST 0x20 +#define ENPHASEMIS 0x10 +#define ENBUSFREE 0x08 +#define ENSCSIPERR 0x04 +#define ENPHASECHG 0x02 +#define ENREQINIT 0x01 /* DMA control 0 */ -#define ENDMA 0x80 -#define _8BIT 0x40 -#define DMA 0x20 -#define WRITE_READ 0x08 -#define INTEN 0x04 -#define RSTFIFO 0x02 -#define SWINT 0x01 +#define ENDMA 0x80 +#define _8BIT 0x40 +#define DMA 0x20 +#define WRITE_READ 0x08 +#define INTEN 0x04 +#define RSTFIFO 0x02 +#define SWINT 0x01 /* DMA control 1 */ -#define PWRDWN 0x80 -#define STK 0x07 /* mask */ +#define PWRDWN 0x80 +#define STK 0x07 /* mask */ /* DMA status */ -#define ATDONE 0x80 -#define WORDRDY 0x40 -#define INTSTAT 0x20 -#define DFIFOFULL 0x10 -#define DFIFOEMP 0x08 +#define ATDONE 0x80 +#define WORDRDY 0x40 +#define INTSTAT 0x20 +#define DFIFOFULL 0x10 +#define DFIFOEMP 0x08 /* BURST control */ -#define BON 0xf0 -#define BOFF 0x0f +#define BON 0xf0 +#define BOFF 0x0f /* TEST REGISTER */ -#define BOFFTMR 0x40 -#define BONTMR 0x20 -#define STCNTH 0x10 -#define STCNTM 0x08 -#define STCNTL 0x04 -#define SCSIBLK 0x02 -#define DMABLK 0x01 +#define BOFFTMR 0x40 +#define BONTMR 0x20 +#define STCNTH 0x10 +#define STCNTM 0x08 +#define STCNTL 0x04 +#define SCSIBLK 0x02 +#define DMABLK 0x01 /* On the AHA-152x board PORTA and PORTB contain some information about the board's configuration. */ typedef union { struct { - unsigned reserved:2; /* reserved */ - unsigned tardisc:1; /* Target disconnect: 0=disabled, 1=enabled */ - unsigned syncneg:1; /* Initial sync neg: 0=disabled, 1=enabled */ - unsigned msgclasses:2; /* Message classes - 0=#4 - 1=#0, #1, #2, #3, #4 - 2=#0, #3, #4 - 3=#0, #4 - */ - unsigned boot:1; /* boot: 0=disabled, 1=enabled */ - unsigned dma:1; /* Transfer mode: 0=PIO; 1=DMA */ - unsigned id:3; /* SCSI-id */ - unsigned irq:2; /* IRQ-Channel: 0,3=12, 1=10, 2=11 */ - unsigned dmachan:2; /* DMA-Channel: 0=0, 1=5, 2=6, 3=7 */ - unsigned parity:1; /* SCSI-parity: 1=enabled 0=disabled */ + unsigned reserved:2; /* reserved */ + unsigned tardisc:1; /* Target disconnect: 0=disabled, 1=enabled */ + unsigned syncneg:1; /* Initial sync neg: 0=disabled, 1=enabled */ + unsigned msgclasses:2; /* Message classes + 0=#4 + 1=#0, #1, #2, #3, #4 + 2=#0, #3, #4 + 3=#0, #4 + */ + unsigned boot:1; /* boot: 0=disabled, 1=enabled */ + unsigned dma:1; /* Transfer mode: 0=PIO; 1=DMA */ + unsigned id:3; /* SCSI-id */ + unsigned irq:2; /* IRQ-Channel: 0,3=12, 1=10, 2=11 */ + unsigned dmachan:2; /* DMA-Channel: 0=0, 1=5, 2=6, 3=7 */ + unsigned parity:1; /* SCSI-parity: 1=enabled 0=disabled */ } fields; unsigned short port; } aha152x_config ; -#define cf_parity fields.parity -#define cf_dmachan fields.dmachan -#define cf_irq fields.irq -#define cf_id fields.id -#define cf_dma fields.dma -#define cf_boot fields.boot -#define cf_msgclasses fields.msgclasses -#define cf_syncneg fields.syncneg -#define cf_tardisc fields.tardisc -#define cf_port port +#define cf_parity fields.parity +#define cf_dmachan fields.dmachan +#define cf_irq fields.irq +#define cf_id fields.id +#define cf_dma fields.dma +#define cf_boot fields.boot +#define cf_msgclasses fields.msgclasses +#define cf_syncneg fields.syncneg +#define cf_tardisc fields.tardisc +#define cf_port port /* Some macros to manipulate ports and their bits */ -#define SETPORT(PORT, VAL) \ - outb( (VAL), (PORT) ) +#define SETPORT(PORT, VAL) outb( (VAL), (PORT) ) +#define SETPORTP(PORT, VAL) outb_p( (VAL), (PORT) ) +#define SETPORTW(PORT, VAL) outw( (VAL), (PORT) ) + +#define GETPORT(PORT) inb( PORT ) +#define GETPORTW(PORT) inw( PORT ) + +#define SETBITS(PORT, BITS) outb( (inb(PORT) | (BITS)), (PORT) ) +#define CLRBITS(PORT, BITS) outb( (inb(PORT) & ~(BITS)), (PORT) ) +#define CLRSETBITS(PORT, CLR, SET) outb( (inb(PORT) & ~(CLR)) | (SET) , (PORT) ) -#define SETPORTP(PORT, VAL) \ - outb_p( (VAL), (PORT) ) - -#define SETPORTW(PORT, VAL) \ - outw( (VAL), (PORT) ) - -#define GETPORT(PORT) \ - inb( PORT ) - -#define GETPORTW(PORT) \ - inw( PORT ) - -#define SETBITS(PORT, BITS) \ - outb( (inb(PORT) | (BITS)), (PORT) ) - -#define CLRBITS(PORT, BITS) \ - outb( (inb(PORT) & ~(BITS)), (PORT) ) - -#define CLRSETBITS(PORT, CLR, SET) \ - outb( (inb(PORT) & ~(CLR)) | (SET) , (PORT) ) - -#define TESTHI(PORT, BITS) \ - ((inb(PORT) & (BITS)) == BITS) - -#define TESTLO(PORT, BITS) \ - ((inb(PORT) & (BITS)) == 0) +#define TESTHI(PORT, BITS) ((inb(PORT) & (BITS)) == BITS) +#define TESTLO(PORT, BITS) ((inb(PORT) & (BITS)) == 0) #ifdef DEBUG_AHA152X enum { - debug_skipports =0x0001, - debug_queue =0x0002, - debug_intr =0x0004, - debug_selection =0x0008, - debug_msgo =0x0010, - debug_msgi =0x0020, - debug_status =0x0040, - debug_cmd =0x0080, - debug_datai =0x0100, - debug_datao =0x0200, - debug_abort =0x0400, - debug_done =0x0800, - debug_biosparam =0x1000, - debug_phases =0x2000, - debug_queues =0x4000, - debug_reset =0x8000, + debug_skipports = 0x0001, + debug_queue = 0x0002, + debug_intr = 0x0004, + debug_selection = 0x0008, + debug_msgo = 0x0010, + debug_msgi = 0x0020, + debug_status = 0x0040, + debug_cmd = 0x0080, + debug_datai = 0x0100, + debug_datao = 0x0200, + debug_abort = 0x0400, + debug_done = 0x0800, + debug_biosparam = 0x1000, + debug_phases = 0x2000, + debug_queues = 0x4000, + debug_reset = 0x8000, }; #endif diff -ur --new-file old/linux/drivers/scsi/aha1542.c new/linux/drivers/scsi/aha1542.c --- old/linux/drivers/scsi/aha1542.c Mon May 6 11:26:10 1996 +++ new/linux/drivers/scsi/aha1542.c Thu Aug 1 14:43:04 1996 @@ -1002,6 +1002,7 @@ cli(); if (request_irq(irq_level,aha1542_intr_handle, 0, "aha1542", NULL)) { printk("Unable to allocate IRQ for adaptec controller.\n"); + restore_flags(flags); goto unregister; } @@ -1009,6 +1010,7 @@ if (request_dma(dma_chan,"aha1542")) { printk("Unable to allocate DMA channel for Adaptec.\n"); free_irq(irq_level, NULL); + restore_flags(flags); goto unregister; } diff -ur --new-file old/linux/drivers/scsi/aic7xxx.c new/linux/drivers/scsi/aic7xxx.c --- old/linux/drivers/scsi/aic7xxx.c Sun May 12 20:52:54 1996 +++ new/linux/drivers/scsi/aic7xxx.c Sat Aug 10 09:44:18 1996 @@ -30,7 +30,7 @@ * ---------------------------------------------------------------- * Modified to include support for wide and twin bus adapters, * DMAing of SCBs, tagged queueing, IRQ sharing, bug fixes, - * and other rework of the code. + * SCB paging, and other rework of the code. * * Parts of this driver are based on the FreeBSD driver by Justin * T. Gibbs. @@ -39,9 +39,9 @@ * * Form: aic7xxx=extended,no_reset * - * -- Daniel M. Eischen, deischen@iworks.InterWorks.org, 04/03/95 + * -- Daniel M. Eischen, deischen@iworks.InterWorks.org, 07/07/96 * - * $Id: aic7xxx.c,v 3.2 1996/05/12 17:28:23 deang Exp $ + * $Id: aic7xxx.c,v 3.4 1996/08/09 15:56:31 deang Exp $ *-M*************************************************************************/ #ifdef MODULE @@ -74,7 +74,7 @@ S_IFDIR | S_IRUGO | S_IXUGO, 2 }; -#define AIC7XXX_C_VERSION "$Revision: 3.2 $" +#define AIC7XXX_C_VERSION "$Revision: 3.4 $" #define NUMBER(arr) (sizeof(arr) / sizeof(arr[0])) #define MIN(a,b) ((a < b) ? a : b) @@ -109,15 +109,9 @@ * set to 2. If you want to implement tagged queueing, ensure * this define is not commented out. * - * o Sharing IRQs - allowed for sharing of IRQs. This will allow - * for multiple aic7xxx host adapters sharing the same IRQ, but - * not for sharing IRQs with other devices. The higher level - * PCI code and interrupt handling needs to be modified to - * support this. - * * o Commands per lun - If tagged queueing is enabled, then you * may want to try increasing AIC7XXX_CMDS_PER_LUN to more - * than 2. By default, we limit the SCBs per lun to 2 with + * than 2. By default, we limit the SCBs per LUN to 2 with * or without tagged queueing enabled. If tagged queueing is * disabled, the sequencer will keep the 2nd SCB in the input * queue until the first one completes - so it is OK to to have @@ -125,10 +119,16 @@ * the sequencer will attempt to send the 2nd SCB to the device * while the first SCB is executing and the device is disconnected. * For adapters limited to 4 SCBs, you may want to actually - * decrease the commands per lun to 1, if you often have more + * decrease the commands per LUN to 1, if you often have more * than 2 devices active at the same time. This will allocate * 1 SCB for each device and ensure that there will always be * a free SCB for up to 4 devices active at the same time. + * When SCB paging is enabled, set the commands per LUN to 8 + * or higher (see SCB paging support below). Note that if + * AIC7XXX_CMDS_PER_LUN is not defined and tagged queueing is + * enabled, the driver will attempt to set the commands per + * LUN using its own heuristic based on the number of available + * SCBs. * * o 3985 support - The 3985 adapter is much like the 3940, but * has three 7870 controllers as opposed to two for the 3940. @@ -140,7 +140,18 @@ * In the near future, we'll modify the driver to reserve 1/3 * of the SCBs for each controller. * - * Daniel M. Eischen, deischen@iworks.InterWorks.org, 01/11/96 + * o SCB paging support - SCB paging is enabled by defining + * AIC7XXX_PAGE_ENABLE. Support for this was taken from the + * FreeBSD driver (by Justin Gibbs) and allows for up to 255 + * active SCBs. This will increase performance when tagged + * queueing is enabled. Note that you should increase the + * AIC7XXX_CMDS_PER_LUN to 8 as most tagged queueing devices + * allow at least this many. + * + * Note that sharing of IRQs is not an option any longer. Linux supports + * it so we support it. + * + * Daniel M. Eischen, deischen@iworks.InterWorks.org, 06/30/96 */ /* Uncomment this for testing twin bus support. */ @@ -149,14 +160,11 @@ /* Uncomment this for tagged queueing. */ /* #define AIC7XXX_TAGGED_QUEUEING */ -/* Uncomment this for allowing sharing of IRQs. */ -#define AIC7XXX_SHARE_IRQS - /* * You can try raising me if tagged queueing is enabled, or lowering * me if you only have 4 SCBs. */ -#define AIC7XXX_CMDS_PER_LUN 2 +/* #define AIC7XXX_CMDS_PER_LUN 8 */ /* Set this to the delay in seconds after SCSI bus reset. */ #define AIC7XXX_RESET_DELAY 15 @@ -170,9 +178,14 @@ /* #define AIC7XXX_PROC_STATS */ /* + * Uncomment the following to enable SCB paging. + */ +/* #define AIC7XXX_PAGE_ENABLE */ + +/* * For debugging the abort/reset code. */ -/* #define AIC7XXX_DEBUG_ABORT */ +#define AIC7XXX_DEBUG_ABORT /* * For general debug messages @@ -189,6 +202,7 @@ AIC_284x, /* VLB aic7770 on 284x, BIOS disabled */ AIC_7850, /* PCI aic7850 */ AIC_7855, /* PCI aic7855 */ + AIC_7860, /* PCI aic7860 (7850 Ultra) */ AIC_7870, /* PCI aic7870 on motherboard */ AIC_7871, /* PCI aic7871 on 294x */ AIC_7872, /* PCI aic7872 on 3940 */ @@ -235,13 +249,14 @@ * Define an array of board names that can be indexed by aha_type. * Don't forget to change this when changing the types! */ -static const char * board_names[] = { +static const char *board_names[] = { "", /* AIC_NONE */ "AIC-7770", /* AIC_7770 */ "AHA-2740", /* AIC_7771 */ "AHA-2840", /* AIC_284x */ "AIC-7850", /* AIC_7850 */ "AIC-7855", /* AIC_7855 */ + "AIC-7850 Ultra", /* AIC_7860 */ "AIC-7870", /* AIC_7870 */ "AHA-2940", /* AIC_7871 */ "AHA-3940", /* AIC_7872 */ @@ -265,8 +280,15 @@ * the command to us. There is no specific driver status for this * condition, but the higher level scsi driver will requeue the * command on a DID_BUS_BUSY error. + * + * Upon further inspection and testing, it seems that DID_BUS_BUSY + * will *always* retry the command. We can get into an infinite loop + * if this happens when we really want some sort of counter that + * will automatically abort/reset the command after so many retries. + * Using DID_ERROR will do just that. (Made by a suggestion by + * Doug Ledford 8/1/96) */ -#define DID_RETRY_COMMAND DID_BUS_BUSY +#define DID_RETRY_COMMAND DID_ERROR /* * EISA/VL-bus stuff @@ -395,6 +417,9 @@ unsigned short checksum; /* word 31 */ }; + +#define SCSI_RESET 0x040 + /* * Pause the sequencer and wait for it to actually stop - this * is important since the sequencer can disable pausing for critical @@ -514,17 +539,18 @@ /*16*/ unsigned long data_count; /*20*/ unsigned char SCSI_cmd_pointer[4] __attribute__ ((packed)); /*24*/ unsigned char SCSI_cmd_length; -#define SCB_PIO_TRANSFER_SIZE 25 /* - * amount we need to upload/download - * via rep in/outsb to perform - * a request sense. The second - * RESERVED byte is initialized to - * 0 in getscb(). +/*25*/ u_char tag; /* Index into our kernel SCB array. + * Also used as the tag for tagged I/O + */ +#define SCB_PIO_TRANSFER_SIZE 26 /* amount we need to upload/download + * via PIO to initialize a transaction. + */ +/*26*/ u_char next; /* Used to thread SCBs awaiting selection + * or disconnected down in the sequencer. */ -/*25*/ u_char next_waiting; /* Used to thread SCBs awaiting selection. */ /*-----------------end of hardware supported fields----------------*/ - struct aic7xxx_scb *next; /* next ptr when in free list */ Scsi_Cmnd *cmd; /* Scsi_Cmnd for this scb */ + struct aic7xxx_scb *q_next; /* next scb in queue */ #define SCB_FREE 0x00 #define SCB_ACTIVE 0x01 #define SCB_ABORTED 0x02 @@ -532,6 +558,12 @@ #define SCB_IMMED 0x08 #define SCB_SENSE 0x10 #define SCB_QUEUED_FOR_DONE 0x40 +#define SCB_PAGED_OUT 0x80 +#define SCB_WAITINGQ 0x100 +#define SCB_ASSIGNEDQ 0x200 +#define SCB_SENTORDEREDTAG 0x400 +#define SCB_IN_PROGRESS (SCB_ACTIVE | SCB_PAGED_OUT | \ + SCB_WAITINGQ | SCB_ASSIGNEDQ) int state; /* current state of scb */ unsigned int position; /* Position in scb array */ struct scatterlist sg; @@ -539,6 +571,14 @@ unsigned char sense_cmd[6]; /* Allocate 6 characters for sense command */ }; +/* + * Define a linked list of SCBs. + */ +typedef struct { + struct aic7xxx_scb *head; + struct aic7xxx_scb *tail; +} scb_queue_type; + static struct { unsigned char errno; const char *errmesg; @@ -564,34 +604,73 @@ */ struct aic7xxx_host { struct Scsi_Host *host; /* pointer to scsi host */ + int host_no; /* SCSI host number */ int base; /* card base address */ - int maxscb; /* hardware SCBs */ - int numscb; /* current number of scbs */ - int extended; /* extended xlate? */ + int maxhscbs; /* hardware SCBs */ + int maxscbs; /* max SCBs (including pageable) */ + int numscbs; /* current number of scbs */ + int activescbs; /* active scbs */ +#define A_SCANNED 0x0001 +#define B_SCANNED 0x0002 +#define EXTENDED_TRANSLATION 0x0004 +#define HAVE_SEEPROM 0x0008 +#define ULTRA_ENABLED 0x0010 +#define PAGE_ENABLED 0x0020 +#define IN_ISR 0x0040 +#define USE_DEFAULTS 0x0080 + unsigned int flags; + unsigned int isr_count; /* Interrupt count */ + unsigned short needsdtr_copy; /* default config */ + unsigned short needsdtr; + unsigned short sdtr_pending; + unsigned short needwdtr_copy; /* default config */ + unsigned short needwdtr; + unsigned short wdtr_pending; + unsigned short orderedtag; + unsigned short discenable; /* Targets allowed to disconnect */ aha_type type; /* card type */ aha_chip_type chip_type; /* chip base type */ - int ultra_enabled; /* Ultra SCSI speed enabled */ - int chan_num; /* for 3940/3985, channel number */ aha_bus_type bus_type; /* normal/twin/wide bus */ - unsigned char a_scanned; /* 0 not scanned, 1 scanned */ - unsigned char b_scanned; /* 0 not scanned, 1 scanned */ - unsigned int isr_count; /* Interrupt count */ - volatile unsigned char unpause; /* unpause value for HCNTRL */ - volatile unsigned char pause; /* pause value for HCNTRL */ - volatile unsigned short needsdtr_copy; /* default config */ - volatile unsigned short needsdtr; - volatile unsigned short sdtr_pending; - volatile unsigned short needwdtr_copy; /* default config */ - volatile unsigned short needwdtr; - volatile unsigned short wdtr_pending; - volatile unsigned short discenable; /* Targets allowed to disconnect */ - struct seeprom_config seeprom; - int have_seeprom; + char * mbase; /* I/O memory address */ + unsigned char chan_num; /* for 3940/3985, channel number */ + unsigned char unpause; /* unpause value for HCNTRL */ + unsigned char pause; /* pause value for HCNTRL */ unsigned char qcntmask; + struct seeprom_config seeprom; struct Scsi_Host *next; /* allow for multiple IRQs */ struct aic7xxx_scb scb_array[AIC7XXX_MAXSCB]; /* active commands */ - struct aic7xxx_scb *free_scb; /* list of free SCBs */ - struct aic7xxx_scb *aborted_scb; /* list of aborted SCBs */ + struct aic7xxx_scb *pagedout_ntscbs[16]; /* + * paged-out, non-tagged scbs + * indexed by target. + */ + scb_queue_type free_scbs; /* + * SCBs assigned to free slot on + * card (no paging required) + */ + scb_queue_type page_scbs; /* + * SCBs that will require paging + * before use (no assigned slot) + */ + scb_queue_type waiting_scbs; /* + * SCBs waiting to be paged and + * started. + */ + scb_queue_type assigned_scbs; /* + * SCBs that were waiting but have + * have now been assigned a slot + * by aic7xxx_free_scb + */ + struct aic7xxx_cmd_queue { + Scsi_Cmnd *head; + Scsi_Cmnd *tail; + } completeq; + struct aic7xxx_device_status { + long last_reset; +#define DEVICE_SUCCESS 0x01 +#define BUS_DEVICE_RESET_PENDING 0x02 + int flags; + int commands_sent; + } device_status[16]; #ifdef AIC7XXX_PROC_STATS /* * Statistics Kept: @@ -618,16 +697,16 @@ struct aic7xxx_host_config { int irq; /* IRQ number */ - int base; /* I/O base */ - int maxscb; /* hardware SCBs */ + int mbase; /* memory base address*/ + int base; /* I/O base address*/ + int maxhscbs; /* hardware SCBs */ + int maxscbs; /* max SCBs (including pageable) */ int unpause; /* unpause value for HCNTRL */ int pause; /* pause value for HCNTRL */ int scsi_id; /* host SCSI ID */ int scsi_id_b; /* host SCSI ID B channel for twin cards */ - int extended; /* extended xlate? */ - int ultra_enabled; /* Ultra SCSI speed enabled */ + unsigned int flags; /* used the same as struct aic7xxx_host flags */ int chan_num; /* for 3940/3985, channel number */ - int use_defaults; /* Use default wide/sync settings. */ unsigned char busrtime; /* bus release time */ unsigned char bus_speed; /* bus speed */ unsigned char qcntmask; @@ -652,39 +731,28 @@ short rate; const char *english; } aic7xxx_syncrates[] = { - { 50, 0x100, "20.0" }, - { 62, 0x110, "16.0" }, - { 75, 0x120, "13.4" }, - { 100, 0x140, "10.0" }, - { 100, 0x000, "10.0" }, - { 125, 0x010, "8.0" }, - { 150, 0x020, "6.67" }, - { 175, 0x030, "5.7" }, - { 200, 0x040, "5.0" }, - { 225, 0x050, "4.4" }, - { 250, 0x060, "4.0" }, - { 275, 0x070, "3.6" } + { 50, 0x100, "20.0" }, + { 62, 0x110, "16.0" }, + { 75, 0x120, "13.4" }, + { 100, 0x000, "10.0" }, + { 125, 0x010, "8.0" }, + { 150, 0x020, "6.67" }, + { 175, 0x030, "5.7" }, + { 200, 0x040, "5.0" }, + { 225, 0x050, "4.4" }, + { 250, 0x060, "4.0" }, + { 275, 0x070, "3.6" } }; static int num_aic7xxx_syncrates = sizeof(aic7xxx_syncrates) / sizeof(aic7xxx_syncrates[0]); #ifdef CONFIG_PCI -static int number_of_39xxs = 0; +static int number_of_3940s = 0; +static int number_of_3985s = 0; #endif CONFIG_PCI #ifdef AIC7XXX_DEBUG -static void -debug(const char *fmt, ...) -{ - va_list ap; - char buf[256]; - - va_start(ap, fmt); - vsprintf(buf, fmt, ap); - printk(buf); - va_end(ap); -} static void debug_config(struct aic7xxx_host_config *p) @@ -700,7 +768,7 @@ scsi_conf = inb(SCSICONF + p->base); /* - * Scale the Data FIFO Threshold and the Bus Release Time; they are + * Scale the Data FIFO Threshhold and the Bus Release Time; they are * stored in formats compatible for writing to sequencer registers. */ dfthresh = p->bus_speed >> 6; @@ -733,6 +801,7 @@ case AIC_7850: case AIC_7855: + case AIC_7860: case AIC_7870: case AIC_7871: case AIC_7872: @@ -743,7 +812,8 @@ case AIC_7882: case AIC_7883: case AIC_7884: - printk("%s%s (PCI-bus):\n", board_names[p->type], BUSW[p->bus_type]); + printk("%s%s (PCI-bus), I/O 0x%x, Mem 0x%x:\n", board_names[p->type], + BUSW[p->bus_type], p->base, p->mbase); break; default: @@ -819,11 +889,16 @@ #endif #else -# define debug(fmt, args...) # define debug_config(x) # define debug_scb(x) #endif AIC7XXX_DEBUG +#define TCL_OF_SCB(x) (((x)->target_channel_lun >> 4) & 0xf), \ + (((x)->target_channel_lun >> 3) & 0x01), \ + ((x)->target_channel_lun & 0x07) + +#define TARGET_INDEX(x) ((x)->target | ((x)->channel << 3)) + /* * XXX - these options apply unilaterally to _all_ 274x/284x/294x * cards in the system. This should be fixed, but then, @@ -831,7 +906,11 @@ */ static unsigned int aic7xxx_extended = 0; /* extended translation on? */ static unsigned int aic7xxx_no_reset = 0; /* no resetting of SCSI bus */ - +static int aic7xxx_irq_trigger = -1; /* + * -1 use board setting + * 0 use edge triggered + * 1 use level triggered + */ /*+F************************************************************************* * Function: * aic7xxx_setup @@ -853,6 +932,7 @@ } options[] = { { "extended", &aic7xxx_extended }, { "no_reset", &aic7xxx_no_reset }, + { "irq_trigger", &aic7xxx_irq_trigger }, { NULL, NULL } }; @@ -1072,6 +1152,8 @@ short period, unsigned char offset, int target, char channel) { int i; + unsigned long ultra_enb_addr; + unsigned char ultra_enb, sxfrctl0; for (i = 0; i < num_aic7xxx_syncrates; i++) { @@ -1081,36 +1163,44 @@ * Watch out for Ultra speeds when ultra is not enabled and * vice-versa. */ - if (p->ultra_enabled) - { - if (!(aic7xxx_syncrates[i].rate & ULTRA_SXFR)) - { - printk ("aic7xxx: Target %d, channel %c, requests %sMHz transfers, " - "but adapter in Ultra mode can only sync at 7.2MHz or " - "above.\n", target, channel, aic7xxx_syncrates[i].english); - break; /* Use asynchronous transfers. */ - } - } - else + if (!(p->flags & ULTRA_ENABLED) && + (aic7xxx_syncrates[i].rate & ULTRA_SXFR)) { /* - * Check for an Ultra device trying to negotiate an Ultra rate - * on an adapter with Ultra mode disabled. + * This should only happen if the drive is the first to negotiate + * and chooses a high rate. We'll just move down the table until + * we hit a non ultra speed. */ - if (aic7xxx_syncrates[i].rate & ULTRA_SXFR) - { - /* - * This should only happen if the driver is the first to negotiate - * and chooses a high rate. We'll just move down the table until - * we hit a non Ultra speed. - */ - continue; - } + continue; } *scsirate = (aic7xxx_syncrates[i].rate) | (offset & 0x0F); - printk("aic7xxx: Target %d, channel %c, now synchronous at %sMHz, " - "offset(0x%x).\n", - target, channel, aic7xxx_syncrates[i].english, offset); + + /* + * Ensure Ultra mode is set properly for this target. + */ + ultra_enb_addr = ULTRA_ENB; + if ((channel == 'B') || (target > 7)) + { + ultra_enb_addr++; + } + ultra_enb = inb(p->base + ultra_enb_addr); + sxfrctl0 = inb(p->base + SXFRCTL0); + if (aic7xxx_syncrates[i].rate & ULTRA_SXFR) + { + ultra_enb |= 0x01 << (target & 0x07); + sxfrctl0 |= ULTRAEN; + } + else + { + ultra_enb &= ~(0x01 << (target & 0x07)); + sxfrctl0 &= ~ULTRAEN; + } + outb(ultra_enb, p->base + ultra_enb_addr); + outb(sxfrctl0, p->base + SXFRCTL0); + + printk("scsi%d: Target %d, channel %c, now synchronous at %sMHz, " + "offset %d.\n", p->host_no, target, channel, + aic7xxx_syncrates[i].english, offset); return; } } @@ -1119,8 +1209,8 @@ * Default to asynchronous transfer */ *scsirate = 0; - printk("aic7xxx: Target %d, channel %c, using asynchronous transfers.\n", - target, channel); + printk("scsi%d: Target %d, channel %c, using asynchronous transfers.\n", + p->host_no, target, channel); } /*+F************************************************************************* @@ -1133,11 +1223,8 @@ static inline void aic7xxx_putscb(struct aic7xxx_host *p, struct aic7xxx_scb *scb) { - unsigned char curscb; int base = p->base; - curscb = inb(SCBPTR + base); - outb(scb->position, SCBPTR + base); outb(SCBAUTO, SCBCNT + base); /* @@ -1158,7 +1245,6 @@ } outb(0, SCBCNT + base); - outb(curscb, SCBPTR + base); } /*+F************************************************************************* @@ -1183,6 +1269,75 @@ /*+F************************************************************************* * Function: + * scbq_init + * + * Description: + * SCB queue initialization. + * + *-F*************************************************************************/ +static inline void +scbq_init(scb_queue_type *queue) +{ + queue->head = NULL; + queue->tail = NULL; +} + +/*+F************************************************************************* + * Function: + * scbq_insert_head + * + * Description: + * Add an SCB to the head of the list. + * + *-F*************************************************************************/ +static inline void +scbq_insert_head(scb_queue_type *queue, struct aic7xxx_scb *scb) +{ + scb->q_next = queue->head; + queue->head = scb; + if (queue->tail == NULL) /* If list was empty, update tail. */ + queue->tail = queue->head; +} + +/*+F************************************************************************* + * Function: + * scbq_remove_head + * + * Description: + * Remove an SCB from the head of the list. + * + *-F*************************************************************************/ +static inline void +scbq_remove_head(scb_queue_type *queue) +{ + if (queue->head != NULL) + queue->head = queue->head->q_next; + if (queue->head == NULL) /* If list is now empty, update tail. */ + queue->tail = NULL; +} + +/*+F************************************************************************* + * Function: + * scbq_insert_tail + * + * Description: + * Add an SCB at the tail of the list. + * + *-F*************************************************************************/ +static inline void +scbq_insert_tail(scb_queue_type *queue, struct aic7xxx_scb *scb) +{ + scb->q_next = NULL; + if (queue->tail != NULL) /* Add the scb at the end of the list. */ + queue->tail->q_next = scb; + + queue->tail = scb; /* Update the tail. */ + if (queue->head == NULL) /* If list was empty, update head. */ + queue->head = queue->tail; +} + +/*+F************************************************************************* + * Function: * aic7xxx_match_scb * * Description: @@ -1198,8 +1353,8 @@ char chan = (scb->target_channel_lun & SELBUSB) ? 'B' : 'A'; #ifdef AIC7XXX_DEBUG_ABORT - printk ("aic7xxx: (match_scb) comparing target/channel %d/%c to scb %d/%c\n", - target, channel, targ, chan); + printk("aic7xxx: (match_scb) comparing target/channel %d/%c to scb %d/%c\n", + target, channel, targ, chan); #endif if (target == ALL_TARGETS) { @@ -1250,10 +1405,6 @@ unsigned char active; unsigned long active_port = ACTIVE_A + base; -#ifdef 0 - printk ("aic7xxx: (unbusy_target) target/channel %d/%c\n", - target, channel); -#endif if ((target > 0x07) || (channel == 'B')) { /* @@ -1269,6 +1420,164 @@ /*+F************************************************************************* * Function: + * aic7xxx_allocate_scb + * + * Description: + * Get a free SCB either from one already assigned to a hardware + * slot, or one that will require an SCB to be paged out before + * use. If there are none, attempt to allocate a new one. + *-F*************************************************************************/ +static struct aic7xxx_scb * +aic7xxx_allocate_scb(struct aic7xxx_host *p) +{ + struct aic7xxx_scb *scbp = NULL; + int maxscbs; + + scbp = p->free_scbs.head; + if (scbp != NULL) + { + scbq_remove_head(&p->free_scbs); + } + else + { + /* + * This should always be NULL if paging is not enabled. + */ + scbp = p->page_scbs.head; + if (scbp != NULL) + { + scbq_remove_head(&p->page_scbs); + } + else + { + /* + * Set limit the SCB allocation to the maximum number of + * hardware SCBs if paging is not enabled; otherwise use + * the maximum (255). + */ + if (p->flags & PAGE_ENABLED) + maxscbs = p->maxscbs; + else + maxscbs = p->maxhscbs; + if (p->numscbs < maxscbs) + { + scbp = &(p->scb_array[p->numscbs]); + memset(scbp, 0, sizeof(*scbp)); + scbp->tag = p->numscbs; + if (p->numscbs < p->maxhscbs) + scbp->position = p->numscbs; + else + scbp->position = SCB_LIST_NULL; + p->numscbs++; + } + } + } + if (scbp != NULL) + { +#ifdef AIC7XXX_DEBUG + p->activescbs++; +#endif + } + return (scbp); +} + +/*+F************************************************************************* + * Function: + * aic7xxx_queue_cmd_complete + * + * Description: + * Due to race conditions present in the SCSI subsystem, it is easier + * to queue completed commands, then call scsi_done() on them when + * we're finished. This function queues the completed commands. + *-F*************************************************************************/ +static inline void +aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, Scsi_Cmnd *cmd) +{ + if (p->completeq.tail == NULL) + p->completeq.head = cmd; + else + p->completeq.tail->host_scribble = (char *) cmd; + p->completeq.tail = cmd; +} + +/*+F************************************************************************* + * Function: + * aic7xxx_done_cmds_complete + * + * Description: + * Process the completed command queue. + *-F*************************************************************************/ +static inline void +aic7xxx_done_cmds_complete(struct aic7xxx_host *p) +{ + Scsi_Cmnd *cmd; + + while (p->completeq.head != NULL) + { + cmd = p->completeq.head; + p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble; + cmd->host_scribble = NULL; + cmd->scsi_done(cmd); + } + p->completeq.tail = NULL; +} + +/*+F************************************************************************* + * Function: + * aic7xxx_free_scb + * + * Description: + * Free the scb and update the page, waiting, free scb lists. + *-F*************************************************************************/ +static void +aic7xxx_free_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb) +{ + struct aic7xxx_scb *wscb; + + scb->state = SCB_FREE; + scb->cmd = NULL; + scb->control = 0; + scb->state = 0; + + if (scb->position == SCB_LIST_NULL) + { + scbq_insert_head(&p->page_scbs, scb); + } + else + { + /* + * If there are any SCBS on the waiting queue, assign the slot of this + * "freed" SCB to the first one. We'll run the waiting queues after + * all command completes for a particular interrupt are completed or + * when we start another command. + */ + wscb = p->waiting_scbs.head; + if (wscb != NULL) + { + scbq_remove_head(&p->waiting_scbs); + wscb->position = scb->position; + scbq_insert_tail(&p->assigned_scbs, wscb); + wscb->state = (wscb->state & ~SCB_WAITINGQ) | SCB_ASSIGNEDQ; + + /* + * The "freed" SCB will need to be assigned a slot before being + * used, so put it in the page_scbs queue. + */ + scb->position = SCB_LIST_NULL; + scbq_insert_head(&p->page_scbs, scb); + } + else + { + scbq_insert_head(&p->free_scbs, scb); + } +#ifdef AIC7XXX_DEBUG + p->activescbs--; /* For debugging purposes. */ +#endif + } +} + +/*+F************************************************************************* + * Function: * aic7xxx_done * * Description: @@ -1277,31 +1586,11 @@ static void aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb) { - long flags; Scsi_Cmnd *cmd = scb->cmd; -#ifdef 0 - printk ("aic7xxx: (done) target/channel %d/%d\n", - cmd->target, cmd->channel); -#endif - /* - * This is a critical section, since we don't want the - * queue routine mucking with the host data. - */ - save_flags(flags); - cli(); - - /* - * Process the command after marking the scb as free - * and adding it to the free list. - */ - scb->state = SCB_FREE; - scb->next = p->free_scb; - p->free_scb = scb; - scb->cmd = NULL; + aic7xxx_free_scb(p, scb); + aic7xxx_queue_cmd_complete(p, cmd); - restore_flags(flags); - cmd->scsi_done(cmd); } /*+F************************************************************************* @@ -1313,49 +1602,31 @@ * aborted list, and adds each scb to the free list. *-F*************************************************************************/ static void -aic7xxx_done_aborted_scbs (struct aic7xxx_host *p) +aic7xxx_done_aborted_scbs(struct aic7xxx_host *p) { Scsi_Cmnd *cmd; struct aic7xxx_scb *scb; int i; -#ifdef AIC7XXX_DEBUG_ABORT - int scb_aborted = 0; - printk("aic7xxx: (done_aborted_scbs) calling scsi_done() for aborted scbs\n"); -#endif - - for (i = 0; i < p->numscb; i++) + for (i = 0; i < p->numscbs; i++) { scb = &(p->scb_array[i]); if (scb->state & SCB_QUEUED_FOR_DONE) { #ifdef AIC7XXX_DEBUG_ABORT - if (scb_aborted == 0) - { - printk("aic7xxx: (done_aborted_scbs) Aborting scb %d", scb->position); - scb_aborted++; - } - else - { - printk(", %d", scb->position); - } + printk("aic7xxx: (done_aborted_scbs) Aborting scb %d, TCL=%d/%d/%d\n", + scb->position, TCL_OF_SCB(scb)); #endif /* * Process the command after marking the scb as free * and adding it to the free list. */ - scb->state = SCB_FREE; - scb->next = p->free_scb; - p->free_scb = scb; cmd = scb->cmd; - scb->cmd = NULL; + p->device_status[TARGET_INDEX(cmd)].flags = 0; + aic7xxx_free_scb(p, scb); cmd->scsi_done(cmd); /* call the done function */ } } -#ifdef AIC7XXX_DEBUG_ABORT - if (scb_aborted != 0) - printk("\n"); -#endif } /*+F************************************************************************* @@ -1375,7 +1646,7 @@ next = inb(WAITING_SCBH + base); outb(scb->position, SCBPTR + base); - outb(next, SCB_NEXT_WAITING + base); + outb(next, SCB_NEXT + base); outb(scb->position, WAITING_SCBH + base); outb(curscb, SCBPTR + base); @@ -1391,7 +1662,7 @@ *-F*************************************************************************/ static unsigned char aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb, - unsigned char prev, unsigned char timedout_scb) + unsigned char prev) { unsigned char curscb, next; int target = (scb->target_channel_lun >> 4) & 0x0F; @@ -1403,13 +1674,13 @@ */ curscb = inb(SCBPTR + base); outb(scb->position, SCBPTR + base); - next = inb(SCB_NEXT_WAITING + base); + next = inb(SCB_NEXT + base); /* * Clear the necessary fields */ outb(0, SCB_CONTROL + base); - outb(SCB_LIST_NULL, SCB_NEXT_WAITING + base); + outb(SCB_LIST_NULL, SCB_NEXT + base); aic7xxx_unbusy_target(target, channel, base); /* @@ -1428,7 +1699,7 @@ * Select the scb that pointed to us and update its next pointer. */ outb(prev, SCBPTR + base); - outb(next, SCB_NEXT_WAITING + base); + outb(next, SCB_NEXT + base); } /* * Point us back at the original scb position and inform the SCSI @@ -1438,10 +1709,6 @@ scb->state |= SCB_ABORTED | SCB_QUEUED_FOR_DONE; scb->cmd->result = (DID_RESET << 16); -#ifdef AIC7XXX_DEBUG_ABORT - printk ("aic7xxx: (abort_waiting_scb) target/channel %d/%c, prev %d, " - "to_scb %d, next %d\n", target, channel, prev, timedout_scb, next); -#endif return (next); } @@ -1454,8 +1721,7 @@ * all active and queued scbs for that target/channel. *-F*************************************************************************/ static int -aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel, - unsigned char timedout_scb) +aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel) { int base = p->base; struct aic7xxx_scb *scb; @@ -1469,36 +1735,33 @@ active_scb = inb(SCBPTR + base); #ifdef AIC7XXX_DEBUG_ABORT - printk ("aic7xxx: (reset_device) target/channel %d/%c, to_scb %d, " - "active_scb %d\n", target, channel, timedout_scb, active_scb); + printk("aic7xxx: (reset_device) target/channel %d/%c, active_scb %d\n", + target, channel, active_scb); #endif /* * Search the QINFIFO. */ { int saved_queue[AIC7XXX_MAXSCB]; - int queued = inb(QINCNT + base); + int queued = inb(QINCNT + base) & p->qcntmask; -#ifdef AIC7XXX_DEBUG_ABORT - if (queued) - printk ("aic7xxx: (reset_device) found %d SCBs in queue\n", queued); -#endif for (i = 0; i < (queued - found); i++) { saved_queue[i] = inb(QINFIFO + base); - scb = &(p->scb_array[saved_queue[i]]); + outb(saved_queue[i], SCBPTR + base); + scb = &(p->scb_array[inb(SCB_TAG + base)]); if (aic7xxx_match_scb(scb, target, channel)) { /* * We found an scb that needs to be aborted. */ #ifdef AIC7XXX_DEBUG_ABORT - printk ("aic7xxx: (reset_device) aborting SCB %d\n", saved_queue[i]); + printk("aic7xxx: (reset_device) aborting SCB %d, TCL=%d/%d/%d\n", + saved_queue[i], TCL_OF_SCB(scb)); #endif scb->state |= SCB_ABORTED | SCB_QUEUED_FOR_DONE; scb->cmd->result = (DID_RESET << 16); - outb(scb->position, SCBPTR + base); - outb(0, SCBARRAY + base); + outb(0, SCB_CONTROL + base); i--; found++; } @@ -1521,25 +1784,22 @@ next = inb(WAITING_SCBH + base); /* Start at head of list. */ prev = SCB_LIST_NULL; -#ifdef AIC7XXX_DEBUG_ABORT - printk ("aic7xxx: (reset_device) Searching waiting SCBs, head %d\n", next); -#endif while (next != SCB_LIST_NULL) { - scb = &(p->scb_array[next]); + outb(next, SCBPTR + base); + scb = &(p->scb_array[inb(SCB_TAG + base)]); /* * Select the SCB. */ if (aic7xxx_match_scb(scb, target, channel)) { - next = aic7xxx_abort_waiting_scb(p, scb, prev, timedout_scb); + next = aic7xxx_abort_waiting_scb(p, scb, prev); found++; } else { - outb(scb->position, SCBPTR + base); prev = next; - next = inb(SCB_NEXT_WAITING + base); + next = inb(SCB_NEXT + base); } } } @@ -1549,7 +1809,7 @@ * for this target that are active. These are other (most likely * tagged) commands that were disconnected when the reset occurred. */ - for (i = 0; i < p->numscb; i++) + for (i = 0; i < p->numscbs; i++) { scb = &(p->scb_array[i]); if ((scb->state & SCB_ACTIVE) && aic7xxx_match_scb(scb, target, channel)) @@ -1557,12 +1817,12 @@ /* * Ensure the target is "free" */ -#ifdef AIC7XXX_DEBUG_ABORT - printk ("aic7xxx: (reset_device) freeing disconnected SCB %d\n", i); -#endif aic7xxx_unbusy_target(target, channel, base); - outb(scb->position, SCBPTR + base); - outb(0, SCBARRAY + base); + if (! (scb->state & SCB_PAGED_OUT)) + { + outb(scb->position, SCBPTR + base); + outb(0, SCB_CONTROL + base); + } scb->state |= SCB_ABORTED | SCB_QUEUED_FOR_DONE; scb->cmd->result = (DID_RESET << 16); found++; @@ -1583,9 +1843,6 @@ static void aic7xxx_reset_current_bus(int base) { -#ifdef AIC7XXX_DEBUG_ABORT - printk ("aic7xxx: (reset_current_bus)\n"); -#endif outb(SCSIRSTO, SCSISEQ + base); udelay(1000); outb(0, SCSISEQ + base); @@ -1599,8 +1856,7 @@ * Reset the channel. *-F*************************************************************************/ static int -aic7xxx_reset_channel(struct aic7xxx_host *p, char channel, - unsigned char timedout_scb, int initiate_reset) +aic7xxx_reset_channel(struct aic7xxx_host *p, char channel, int initiate_reset) { int base = p->base; unsigned char sblkctl; @@ -1608,15 +1864,11 @@ unsigned long offset, offset_max; int found; -#ifdef AIC7XXX_DEBUG_ABORT - printk ("aic7xxx: (reset_channel) channel %c, to_scb %d\n", - channel, timedout_scb); -#endif /* * Clean up all the state information for the * pending transactions on this bus. */ - found = aic7xxx_reset_device(p, ALL_TARGETS, channel, timedout_scb); + found = aic7xxx_reset_device(p, ALL_TARGETS, channel); if (channel == 'B') { @@ -1673,8 +1925,8 @@ if (cur_channel != channel) { #ifdef AIC7XXX_DEBUG_ABORT - printk ("aic7xxx: (reset_channel) Stealthily resetting channel %c\n", - channel); + printk("aic7xxx: (reset_channel) Stealthily resetting channel %c\n", + channel); #endif /* * Stealthily reset the other bus without upsetting the current bus @@ -1684,10 +1936,6 @@ { aic7xxx_reset_current_bus(base); } - - /* - * Ensure we don't get a RSTI interrupt from this. - */ outb(CLRSCSIRSTI | CLRSELTIMEO, CLRSINT1 + base); outb(CLRSCSIINT, CLRINT + base); outb(sblkctl, SBLKCTL + base); @@ -1700,29 +1948,25 @@ else { #ifdef AIC7XXX_DEBUG_ABORT - printk ("aic7xxx: (reset_channel) Resetting current channel %c\n", - channel); + printk("aic7xxx: (reset_channel) Resetting current channel %c\n", + channel); #endif if (initiate_reset) { aic7xxx_reset_current_bus(base); } - /* - * Ensure we don't get a RSTI interrupt from this. - */ outb(CLRSCSIRSTI | CLRSELTIMEO, CLRSINT1 + base); outb(CLRSCSIINT, CLRINT + base); - RESTART_SEQUENCER(p); #ifdef AIC7XXX_DEBUG_ABORT - printk ("aic7xxx: (reset_channel) Channel reset, sequencer restarted\n"); + printk("aic7xxx: (reset_channel) Channel reset, sequencer restarted\n"); #endif } /* - * Set the time of last reset. + * Delay by the bus settle time. */ - p->host->last_reset = jiffies; + aic7xxx_delay(AIC7XXX_RESET_DELAY); /* * Now loop through all the SCBs that have been marked for abortion, @@ -1734,74 +1978,217 @@ /*+F************************************************************************* * Function: - * aic7xxx_isr + * aic7xxx_page_scb * * Description: - * SCSI controller interrupt handler. + * Swap in_scbp for out_scbp down in the cards SCB array. + * We assume that the SCB for out_scbp is already selected in SCBPTR. * - * NOTE: Since we declared this using SA_INTERRUPT, interrupts should - * be disabled all through this function unless we say otherwise. *-F*************************************************************************/ -static void -aic7xxx_isr(int irq, void *dev_id, struct pt_regs * regs) +static inline void +aic7xxx_page_scb(struct aic7xxx_host *p, struct aic7xxx_scb *out_scbp, + struct aic7xxx_scb *in_scbp) +{ + int index; + + /* Page-out */ +#if 0 +printk("aic7xxx: Paging out target %d SCB and paging in target %d SCB\n", + out_scbp->cmd->target, in_scbp->cmd->target); +#endif + aic7xxx_getscb(p, out_scbp); + out_scbp->state |= SCB_PAGED_OUT; + if (!(out_scbp->control & TAG_ENB)) + { + /* Stick in non-tagged array */ + index = (out_scbp->target_channel_lun >> 4) | + (out_scbp->target_channel_lun & SELBUSB); + p->pagedout_ntscbs[index] = out_scbp; + } + + /* Page-in */ + in_scbp->position = out_scbp->position; + out_scbp->position = SCB_LIST_NULL; + aic7xxx_putscb(p, in_scbp); + in_scbp->state &= ~SCB_PAGED_OUT; +} + +/*+F************************************************************************* + * Function: + * aic7xxx_run_waiting_queues + * + * Description: + * Scan the assigned_scbs and waiting_scbs queues. For scbs in the + * assigned_scbs queue, we download and start them. For scbs in the + * waiting_scbs queue, we page in as many as we can being careful + * not to cause a deadlock for a reconnecting target. + * + *-F*************************************************************************/ +static inline void +aic7xxx_run_waiting_queues(struct aic7xxx_host *p) { - int base, intstat; - struct aic7xxx_host *p; struct aic7xxx_scb *scb; - unsigned char ha_flags; - short transfer; - unsigned char scsi_id, bus_width; - unsigned char offset, rate, scratch, scratch_offset; - unsigned char max_offset, rej_byte; - unsigned short target_mask; - char channel; - void *addr; - int actual; - int scb_index; - Scsi_Cmnd *cmd; + u_char cur_scb; + u_long base = p->base; + long flags; - p = (struct aic7xxx_host *) aic7xxx_boards[irq]->hostdata; + if ((p->assigned_scbs.head == NULL) && (p->waiting_scbs.head == NULL)) + return; + + save_flags(flags); + cli(); + + PAUSE_SEQUENCER(p); + cur_scb = inb(SCBPTR + base); /* - * Search for the host with a pending interrupt. If we can't find - * one, then we've encountered a spurious interrupt. + * First handle SCBs that are waiting but have been assigned a slot. */ - while ((p != NULL) && !(inb(INTSTAT + p->base) & INT_PEND)) + scb = p->assigned_scbs.head; + while (scb != NULL) { - if (p->next == NULL) + scbq_remove_head(&(p->assigned_scbs)); + outb(scb->position, SCBPTR + base); + aic7xxx_putscb(p, scb); + /* Mark this as an active command. */ + scb->state = (scb->state & ~SCB_ASSIGNEDQ) | SCB_ACTIVE; + outb(scb->position, QINFIFO + base); + scb = p->assigned_scbs.head; + } + + /* Now deal with SCBs that require paging. */ + scb = p->waiting_scbs.head; + if (scb != NULL) + { + u_char disc_scb = inb(DISCONNECTED_SCBH + base); + u_char active = inb(FLAGS + base) & (SELECTED | IDENTIFY_SEEN); + int count = 0; + u_char next_scb; + + while (scb != NULL) { - p = NULL; + /* Attempt to page this SCB in */ + if (disc_scb == SCB_LIST_NULL) + break; + + /* + * Advance disc_scb to the next one in the list. + */ + outb(disc_scb, SCBPTR + base); + next_scb = inb(SCB_NEXT + base); + + /* + * We have to be careful about when we allow an SCB to be paged out. + * There must always be at least one slot availible for a reconnecting + * target in case it references an SCB that has been paged out. Our + * heuristic is that either the disconnected list has at least two + * entries in it or there is one entry and the sequencer is activily + * working on an SCB which implies that it will either complete or + * disconnect before another reconnection can occur. + */ + if ((next_scb != SCB_LIST_NULL) || active) + { + u_char out_scbi; + struct aic7xxx_scb *out_scbp; + + scbq_remove_head(&(p->waiting_scbs)); + + /* + * Find the in-core SCB for the one we're paging out. + */ + out_scbi = inb(SCB_TAG + base); + out_scbp = &(p->scb_array[out_scbi]); + + /* Do the page out and mark the paged in SCB as active. */ + aic7xxx_page_scb(p, out_scbp, scb); + + /* Mark this as an active command. */ + scb->state = (scb->state & ~SCB_WAITINGQ) | SCB_ACTIVE; + + /* Queue the command */ + outb(scb->position, QINFIFO + base); + count++; + + /* Advance to the next disconnected SCB */ + disc_scb = next_scb; + scb = p->waiting_scbs.head; + } + else + scb = NULL; } - else + + if (count) { - p = (struct aic7xxx_host *) p->next->hostdata; + /* + * Update the head of the disconnected list. + */ + outb(disc_scb, DISCONNECTED_SCBH + base); + if (disc_scb != SCB_LIST_NULL) + { + outb(disc_scb, SCBPTR + base); + outb(SCB_LIST_NULL, SCB_PREV + base); + } } } + /* Restore old position */ + outb(cur_scb, SCBPTR + base); + UNPAUSE_SEQUENCER(p); - if (p == NULL) + restore_flags(flags); +} + +/*+F************************************************************************* + * Function: + * aic7xxx_isr + * + * Description: + * SCSI controller interrupt handler. + * + * NOTE: Since we declared this using SA_INTERRUPT, interrupts should + * be disabled all through this function unless we say otherwise. + *-F*************************************************************************/ +static void +aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs) +{ + int base, intstat, actual, scb_index, run_aborted_queue = FALSE; + struct aic7xxx_host *p; + struct aic7xxx_scb *scb = NULL; + short transfer; + unsigned char ha_flags, scsi_id, bus_width; + unsigned char offset, rate, scratch, scratch_offset; + unsigned char max_offset, rej_byte; + unsigned short target_mask; + char channel; + void *addr; + Scsi_Cmnd *cmd; + + p = (struct aic7xxx_host *) aic7xxx_boards[irq]->hostdata; + + /* + * Search for the host with a pending interrupt. If we can't find + * one, then we've encountered a spurious interrupt. + */ + while ((p != NULL) && !(inb(INTSTAT + p->base) & INT_PEND)) { - if (aic7xxx_spurious_count == 1) + if (p->next == NULL) { - aic7xxx_spurious_count = 2; - printk("aic7xxx: (aic7xxx_isr) Encountered spurious interrupt.\n"); - return; + p = NULL; } else { - /* - * The best we can do is to set p back to head of list and process - * the erroneous interrupt - most likely a BRKADRINT. - */ - p = (struct aic7xxx_host *) aic7xxx_boards[irq]->hostdata; + p = (struct aic7xxx_host *) p->next->hostdata; } } + if (p == NULL) + return; + /* * Keep track of interrupts for /proc/scsi */ p->isr_count++; - if (!p->a_scanned && (p->isr_count == 1)) + if (!(p->flags & A_SCANNED) && (p->isr_count == 1)) { /* * We must only have one card at this IRQ and it must have been @@ -1820,21 +2207,26 @@ */ intstat = inb(INTSTAT + base); + /* + * Indicate that we're in the interrupt handler. + */ + p->flags |= IN_ISR; + if (intstat & BRKADRINT) { int i; unsigned char errno = inb(ERROR + base); - printk("aic7xxx: (aic7xxx_isr) BRKADRINT error(0x%x):\n", errno); + printk(KERN_ERR "scsi%d: BRKADRINT error(0x%x):\n", p->host_no, errno); for (i = 0; i < NUMBER(hard_error); i++) { if (errno & hard_error[i].errno) { - printk(" %s\n", hard_error[i].errmesg); + printk(KERN_ERR " %s\n", hard_error[i].errmesg); } } - panic("aic7xxx: (aic7xxx_isr) BRKADRINT, error(0x%x) seqaddr(0x%x).\n", - inb(ERROR + base), (inb(SEQADDR1 + base) << 8) | inb(SEQADDR0 + base)); + panic("scsi%d: BRKADRINT, error 0x%x, seqaddr 0x%x.\n", p->host_no, + inb(ERROR + base), (inb(SEQADDR1 + base) << 8) | inb(SEQADDR0 + base)); } if (intstat & SEQINT) @@ -1858,43 +2250,234 @@ switch (intstat & SEQINT_MASK) { + case NO_MATCH: + if (p->flags & PAGE_ENABLED) + { + /* SCB Page-in request */ + struct aic7xxx_scb *outscb; + u_char arg_1 = inb(ARG_1 + base); + int use_disconnected = FALSE; + + /* + * The sequencer expects this value upon return. Assume + * we will find the paged out SCB and set the value now. + * If we don't, and one of the methods used to acquire an + * SCB calls aic7xxx_done(), we will end up in our queue + * routine and unpause the sequencer without giving it the + * correct return value, which causes a hang. + */ + outb(SCB_PAGEDIN, RETURN_1 + base); + if (arg_1 == SCB_LIST_NULL) + { + /* Non-tagged command */ + int index = scsi_id; + if (channel == 'B') + { + index |= SELBUSB; + } + scb = p->pagedout_ntscbs[index]; + } + else + scb = &(p->scb_array[arg_1]); + + if (!(scb->state & SCB_PAGED_OUT)) + { + printk(KERN_WARNING "scsi%d: No active paged-out SCB for reconnecting " + "target %d, channel %c - Issuing ABORT. SAVED_TCL(0x%x).\n", + p->host_no, scsi_id, channel, inb(SAVED_TCL + base)); + aic7xxx_unbusy_target(scsi_id, channel, base); + outb(CLRSELTIMEO, CLRSINT1 + base); + outb(0, RETURN_1 + base); + break; + } + + /* + * Now to pick the SCB to page out. Either take a free SCB, an + * assigned SCB, an SCB that just completed, or the first one + * on the disconnected SCB list. + */ + if (p->free_scbs.head != NULL) + { + outscb = p->free_scbs.head; + scbq_remove_head(&p->free_scbs); + scb->position = outscb->position; + outscb->position = SCB_LIST_NULL; + scbq_insert_head(&p->page_scbs, outscb); + outb(scb->position, SCBPTR + base); + aic7xxx_putscb(p, scb); + scb->state &= ~SCB_PAGED_OUT; + } + else if (p->assigned_scbs.head != NULL) + { + outscb = p->assigned_scbs.head; + scbq_remove_head(&p->assigned_scbs); + scb->position = outscb->position; + outscb->position = SCB_LIST_NULL; + scbq_insert_head(&p->waiting_scbs, outscb); + outscb->state = (outscb->state & ~SCB_ASSIGNEDQ) | SCB_WAITINGQ; + outb(scb->position, SCBPTR + base); + aic7xxx_putscb(p, scb); + scb->state &= ~SCB_PAGED_OUT; + } + else if (intstat & CMDCMPLT) + { + int scb_index; + + outb(CLRCMDINT, CLRINT + base); + scb_index = inb(QOUTFIFO + base); + if (!(inb(QOUTCNT + base) & p->qcntmask)) + { + intstat &= ~CMDCMPLT; + } + outscb = &(p->scb_array[scb_index]); + if (!(outscb->state & SCB_ACTIVE)) + { + printk(KERN_WARNING "scsi%d: No command for completed SCB %d " + "during NO_MATCH interrupt\n", scb_index, p->host_no); + use_disconnected = TRUE; + } + else + { + scb->position = outscb->position; + outscb->position = SCB_LIST_NULL; + outb(scb->position, SCBPTR + base); + aic7xxx_putscb(p, scb); + scb->state &= ~SCB_PAGED_OUT; + outscb->cmd->result |= (aic7xxx_error(outscb->cmd) << 16); + if ((outscb->cmd->flags & WAS_SENSE) && + !(outscb->cmd->flags & ASKED_FOR_SENSE)) + { + /* + * Got sense information. + */ + outscb->cmd->flags &= ASKED_FOR_SENSE; + } + p->device_status[TARGET_INDEX(outscb->cmd)].flags + |= DEVICE_SUCCESS; + aic7xxx_done(p, outscb); + } + } + else + { + use_disconnected = TRUE; + } + if (use_disconnected) + { + u_char tag; + u_char next; + u_char disc_scb = inb(DISCONNECTED_SCBH + base); + if (disc_scb != SCB_LIST_NULL) + { + outb(disc_scb, SCBPTR + base); + tag = inb(SCB_TAG + base); + outscb = &(p->scb_array[tag]); + next = inb(SCB_NEXT + base); + if (next != SCB_LIST_NULL) + { + outb(next, SCBPTR + base); + outb(SCB_LIST_NULL, SCB_PREV + base); + outb(disc_scb, SCBPTR + base); + } + outb(next, DISCONNECTED_SCBH + base); + aic7xxx_page_scb(p, outscb, scb); + } + else if (inb(QINCNT + base) & p->qcntmask) + { + /* Pull one of our queued commands as a last resort. */ + disc_scb = inb(QINFIFO + base); + outb(disc_scb, SCBPTR + base); + tag = inb(SCB_TAG + base); + outscb = &p->scb_array[tag]; + if ((outscb->control & 0x23) != TAG_ENB) + { + /* + * This is not a simple tagged command so its position + * in the queue matters. Take the command at the end of + * the queue instead. + */ + int i; + int saved_queue[AIC7XXX_MAXSCB]; + int queued = inb(QINCNT + base) & p->qcntmask; + + /* Count the command we removed already */ + saved_queue[0] = disc_scb; + queued++; + + /* Empty the input queue. */ + for (i = 1; i < queued; i++) + { + saved_queue[i] = inb(QINFIFO + base); + } + + /* Put everyone back but the last entry. */ + queued--; + for (i = 0; i < queued; i++) + { + outb(saved_queue[i], QINFIFO + base); + } + + outb(saved_queue[queued], SCBPTR + base); + tag = inb(SCB_TAG + base); + outscb = &p->scb_array[tag]; + } + scb->position = outscb->position; + outscb->position = SCB_LIST_NULL; + scbq_insert_head(&p->waiting_scbs, outscb); + outscb->state |= SCB_WAITINGQ; + aic7xxx_putscb(p, scb); + scb->state &= ~SCB_PAGED_OUT; + } + else + { + printk(KERN_WARNING "scsi%d: Page-in request with no candidates " + "target %d, channel %c - Issuing ABORT. SAVED_TCL(0x%x).\n", + p->host_no, scsi_id, channel, inb(SAVED_TCL + base)); + aic7xxx_unbusy_target(scsi_id, channel, base); + outb(CLRSELTIMEO, CLRSINT1 + base); + outb(0, RETURN_1 + base); + } + } + } + else + { + printk(KERN_WARNING "scsi%d: No active SCB for reconnecting " + "target %d, channel %c - Issuing ABORT. SAVED_TCL(0x%x).\n", + p->host_no, scsi_id, channel, inb(SAVED_TCL + base)); + aic7xxx_unbusy_target(scsi_id, channel, base); + outb(0, SCB_CONTROL + base); + outb(CLRSELTIMEO, CLRSINT1 + base); + outb(0, RETURN_1 + base); + } + break; + case BAD_PHASE: - panic("aic7xxx: (aic7xxx_isr) Unknown scsi bus phase.\n"); + panic("scsi%d: Unknown scsi bus phase.\n", p->host_no); break; case SEND_REJECT: rej_byte = inb(REJBYTE + base); if ((rej_byte & 0xF0) == 0x20) { - scb_index = inb(SCBPTR + base); + scb_index = inb(SCB_TAG + base); scb = &(p->scb_array[scb_index]); - printk("aic7xxx: Warning - Tagged message received without identify." + printk(KERN_WARNING "scsi%d: Tagged message received without identify." "Disabling tagged commands for target %d channel %c.\n", - scsi_id, channel); + p->host_no, scsi_id, channel); scb->cmd->device->tagged_supported = 0; scb->cmd->device->tagged_queue = 0; } else { - debug("aic7xxx: Warning - Rejecting unknown message (0x%x) received " - "from target %d channel %c.\n", rej_byte, scsi_id, channel); + printk(KERN_WARNING "scsi%d: Rejecting unknown message (0x%x) received " + "from target %d channel %c.\n", + p->host_no, rej_byte, scsi_id, channel); } break; case NO_IDENT: - panic("aic7xxx: Target %d, channel %c, did not send an IDENTIFY " - "message. SAVED_TCL(0x%x).\n", - scsi_id, channel, inb(SAVED_TCL + base)); - break; - - case NO_MATCH: - printk("aic7xxx: No active SCB for reconnecting target %d, " - "channel %c - Issuing ABORT. SAVED_TCL(0x%x).\n", - scsi_id, channel, inb(SAVED_TCL + base)); - aic7xxx_unbusy_target(scsi_id, channel, base); - outb(0, SCBARRAY + base); - outb(CLRSELTIMEO, CLRSINT1 + base); - RESTART_SEQUENCER(p); + panic("scsi%d: Target %d, channel %c, did not send an IDENTIFY " + "message. SAVED_TCL 0x%x.\n", + p->host_no, scsi_id, channel, inb(SAVED_TCL + base)); break; case SDTR_MSG: @@ -1967,8 +2550,8 @@ case WDTR_MSG: { bus_width = inb(ARG_1 + base); - printk("aic7xxx: Received MSG_WDTR, Target %d, channel %c " - "needwdtr(0x%x).\n", scsi_id, channel, p->needwdtr); + printk(KERN_INFO "scsi%d: Received MSG_WDTR, Target %d, channel %c " + "needwdtr(0x%x).\n", p->host_no, scsi_id, channel, p->needwdtr); scratch = inb(TARG_SCRATCH + base + scratch_offset); if (p->wdtr_pending & target_mask) @@ -1984,15 +2567,15 @@ break; case BUS_16_BIT: - printk("aic7xxx: Target %d, channel %c, using 16 bit " - "transfers.\n", scsi_id, channel); + printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 bit " + "transfers.\n", p->host_no, scsi_id, channel); scratch |= 0x80; break; case BUS_32_BIT: outb(SEND_REJ, RETURN_1 + base); - printk("aic7xxx: Target %d, channel %c, requesting 32 bit " - "transfers, rejecting...\n", scsi_id, channel); + printk(KERN_INFO "scsi%d: Target %d, channel %c, requesting 32 bit " + "transfers, rejecting...\n", p->host_no, scsi_id, channel); break; } } @@ -2001,7 +2584,7 @@ /* * Send our own WDTR in reply. */ - printk("aic7xxx: Will send WDTR!!\n"); + printk(KERN_INFO "scsi%d: Will send WDTR!!\n", p->host_no); switch (bus_width) { case BUS_8_BIT: @@ -2016,8 +2599,8 @@ /* Yes, we mean to fall thru here. */ case BUS_16_BIT: - printk("aic7xxx: Target %d, channel %c, using 16 bit " - "transfers.\n", scsi_id, channel); + printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 bit " + "transfers.\n", p->host_no, scsi_id, channel); scratch |= 0x80; break; } @@ -2049,8 +2632,9 @@ scratch &= 0x7F; p->needwdtr &= ~target_mask; p->wdtr_pending &= ~target_mask; - printk("aic7xxx: Target %d, channel %c, refusing WIDE negotiation. " - "Using 8 bit transfers.\n", scsi_id, channel); + printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing WIDE " + "negotiation; using 8 bit transfers.\n", + p->host_no, scsi_id, channel); } else { @@ -2062,9 +2646,9 @@ scratch &= 0xF0; p->needsdtr &= ~target_mask; p->sdtr_pending &= ~target_mask; - printk("aic7xxx: Target %d, channel %c, refusing synchronous " - "negotiation. Using asynchronous transfers.\n", - scsi_id, channel); + printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing " + "synchronous negotiation; using asynchronous transfers.\n", + p->host_no, scsi_id, channel); } /* * Otherwise, we ignore it. @@ -2076,19 +2660,25 @@ } case BAD_STATUS: - scb_index = inb(SCBPTR + base); + /* The sequencer will notify us when a command has an error that + * would be of interest to the kernel. This allows us to leave + * the sequencerrunning in the common case of command completes + * without error. + */ + + scb_index = inb(SCB_TAG + base); scb = &(p->scb_array[scb_index]); outb(0, RETURN_1 + base); /* CHECK_CONDITION may change this */ if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL)) { - printk("aic7xxx: Referenced SCB not valid during SEQINT(0x%x) " - "scb(%d) state(0x%x) cmd(0x%x).\n", + printk(KERN_WARNING "scsi%d: Referenced SCB not valid during " + "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%x.\n", p->host_no, intstat, scb_index, scb->state, (unsigned int) scb->cmd); } else { cmd = scb->cmd; - aic7xxx_getscb(p, scb); + scb->target_status = inb(SCB_TARGET_STATUS + base); aic7xxx_status(cmd) = scb->target_status; cmd->result |= scb->target_status; @@ -2096,14 +2686,13 @@ switch (status_byte(scb->target_status)) { case GOOD: - printk("aic7xxx: Interrupted for status of GOOD???\n"); + printk(KERN_WARNING "aic7xxx: Interrupted for status of GOOD???\n"); break; case CHECK_CONDITION: if ((aic7xxx_error(cmd) == 0) && !(cmd->flags & WAS_SENSE)) { unsigned char tcl; - unsigned char control; void *req_buf; tcl = scb->target_channel_lun; @@ -2122,10 +2711,8 @@ scb->sense_sg.length = sizeof(cmd->sense_buffer); req_buf = &scb->sense_sg; cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]); - control = scb->control; - memset(scb, 0, SCB_PIO_TRANSFER_SIZE); - scb->control = control & DISCENB; + scb->control = scb->control & DISCENB; scb->target_channel_lun = tcl; addr = scb->sense_cmd; scb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]); @@ -2138,7 +2725,6 @@ memcpy(scb->data_pointer, &(scb->sense_sg.address), 4); aic7xxx_putscb(p, scb); - outb(SCB_LIST_NULL, SCB_NEXT_WAITING + base); /* * Ensure that the target is "BUSY" so we don't get overlapping * commands if we happen to be doing tagged I/O. @@ -2159,7 +2745,8 @@ break; case BUSY: - printk("aic7xxx: Target busy.\n"); + printk(KERN_WARNING "scsi%d: Target busy, TCL=0x%x.\n", + p->host_no, scb->target_channel_lun); if (!aic7xxx_error(cmd)) { aic7xxx_error(cmd) = DID_BUS_BUSY; @@ -2167,16 +2754,14 @@ break; case QUEUE_FULL: - printk("aic7xxx: Queue full.\n"); - if (!aic7xxx_error(cmd)) - { - aic7xxx_error(cmd) = DID_RETRY_COMMAND; - } + printk(KERN_WARNING "scsi%d: Queue full.\n", p->host_no); + scb->state |= SCB_ASSIGNEDQ; + scbq_insert_tail(&p->assigned_scbs, scb); break; default: - printk("aic7xxx: Unexpected target status(0x%x).\n", - scb->target_status); + printk(KERN_WARNING "scsi%d: Unexpected target status 0x%x.\n", + p->host_no, scb->target_status); if (!aic7xxx_error(cmd)) { aic7xxx_error(cmd) = DID_RETRY_COMMAND; @@ -2187,12 +2772,12 @@ break; case RESIDUAL: - scb_index = inb(SCBPTR + base); + scb_index = inb(SCB_TAG + base); scb = &(p->scb_array[scb_index]); if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL)) { - printk("aic7xxx: Referenced SCB not valid during SEQINT(0x%x) " - "scb(%d) state(0x%x) cmd(0x%x).\n", + printk(KERN_WARNING "scsi%d: Referenced SCB not valid during " + "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%x.\n", p->host_no, intstat, scb_index, scb->state, (unsigned int) scb->cmd); } else @@ -2218,9 +2803,9 @@ if (actual < cmd->underflow) { - printk("aic7xxx: Target %d underflow - " - "Wanted (at least) (%u) got(%u) count(%d).\n", - cmd->target, cmd->underflow, actual, + printk(KERN_WARNING "scsi%d: Target %d underflow - " + "Wanted at least %u, got %u, residual SG count %d.\n", + p->host_no, cmd->target, cmd->underflow, actual, inb(SCB_RESID_SGCNT + base)); aic7xxx_error(cmd) = DID_RETRY_COMMAND; aic7xxx_status(cmd) = scb->target_status; @@ -2230,12 +2815,12 @@ break; case ABORT_TAG: - scb_index = inb(SCBPTR + base); + scb_index = inb(SCB_TAG + base); scb = &(p->scb_array[scb_index]); if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL)) { - printk("aic7xxx: Referenced SCB not valid during SEQINT(0x%x) " - "scb(%d) state(0x%x) cmd(0x%x)\n", + printk(KERN_WARNING "scsi%d: Referenced SCB not valid during " + "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%x\n", p->host_no, intstat, scb_index, scb->state, (unsigned int) scb->cmd); } else @@ -2245,8 +2830,8 @@ * We didn't receive a valid tag back from the target * on a reconnect. */ - printk("aic7xxx: Invalid tag received on target %d, channel %c, " - "lun %d - Sending ABORT_TAG.\n", + printk("scsi%d: Invalid tag received on target %d, channel %c, " + "lun %d - Sending ABORT_TAG.\n", p->host_no, scsi_id, channel, cmd->lun & 0x07); cmd->result = (DID_RETRY_COMMAND << 16); @@ -2255,12 +2840,12 @@ break; case AWAITING_MSG: - scb_index = inb(SCBPTR + base); + scb_index = inb(SCB_TAG + base); scb = &(p->scb_array[scb_index]); if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL)) { - printk("aic7xxx: Referenced SCB not valid during SEQINT(0x%x) " - "scb(%d) state(0x%x) cmd(0x%x).\n", + printk(KERN_WARNING "scsi%d: Referenced SCB not valid during " + "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%x.\n", p->host_no, intstat, scb_index, scb->state, (unsigned int) scb->cmd); } else @@ -2281,18 +2866,18 @@ } else { - panic("aic7xxx: AWAITING_SCB for an SCB that does " - "not have a waiting message.\n"); + panic("scsi%d: AWAITING_SCB for an SCB that does " + "not have a waiting message.\n", p->host_no); } } break; case IMMEDDONE: - scb_index = inb(SCBPTR + base); + scb_index = inb(SCB_TAG + base); scb = &(p->scb_array[scb_index]); #ifdef AIC7XXX_DEBUG_ABORT - printk ("aic7xxx: (isr) received IMMEDDONE for target %d, scb %d, state %d\n", - scsi_id, scb_index, scb->state); + printk("aic7xxx: received IMMEDDONE for target %d, scb %d, state %d\n", + scsi_id, scb_index, scb->state); #endif if (scb->state & SCB_DEVICE_RESET) { @@ -2309,15 +2894,33 @@ scratch = inb(TARG_SCRATCH + base + scratch_offset); scratch &= SXFR; outb(scratch, TARG_SCRATCH + base + scratch_offset); - found = aic7xxx_reset_device(p, (int) scsi_id, channel, SCB_LIST_NULL); - aic7xxx_done_aborted_scbs (p); + found = aic7xxx_reset_device(p, (int) scsi_id, channel); + printk(KERN_INFO "scsi%d: Bus Device Reset delivered, %d SCBs " + "aborted.\n", p->host_no, found); + /* Indicate that we want to call aic7xxx_done_aborted_scbs() */ + run_aborted_queue = TRUE; } else { - panic("aic7xxx: Immediate complete for unknown operation.\n"); + panic("scsi%d: Immediate complete for unknown operation.\n", + p->host_no); } break; + case DATA_OVERRUN: + { + unsigned int overrun; + + scb = &p->scb_array[inb(base + SCB_TAG)]; + overrun = inb(base + STCNT0) | (inb(base + STCNT1) << 8) | + (inb(base + STCNT2) << 16); + overrun =0x00FFFFFF - overrun; + printk(KERN_WARNING "scsi%d: data overrun of %d bytes detected; forcing " + "a retry.\n", p->host_no, overrun); + aic7xxx_error(scb->cmd) = DID_RETRY_COMMAND; + break; + } + #if AIC7XXX_NOT_YET /* XXX Fill these in later */ case MESG_BUFFER_BUSY: @@ -2327,8 +2930,8 @@ #endif default: /* unknown */ - debug("aic7xxx: SEQINT, INTSTAT(0x%x) SCSISIGI(0x%x).\n", - intstat, inb(SCSISIGI + base)); + printk(KERN_WARNING "scsi%d: SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n", + p->host_no, intstat, inb(SCSISIGI + base)); break; } @@ -2349,11 +2952,23 @@ channel = 'B'; } - scb_index = inb(SCBPTR + base); + scb_index = inb(SCB_TAG + base); scb = &(p->scb_array[scb_index]); - if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL)) + if (status & SCSIRSTI) + { + PAUSE_SEQUENCER(p); + printk(KERN_WARNING "scsi%d: SCSIINT - Someone reset channel %c.\n", + p->host_no, channel); + /* + * Go through and abort all commands for the channel, but do not + * reset the channel again. + */ + aic7xxx_reset_channel(p, channel, FALSE); + run_aborted_queue = TRUE; + } + else if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL)) { - printk("aic7xxx: No command for SCB (SCSIINT).\n"); + printk(KERN_WARNING "scsi%d: SCSIINT - No command for SCB.\n", p->host_no); /* * Turn off the interrupt and set status to zero, so that it * falls through the rest of the SCSIINT code. @@ -2363,16 +2978,6 @@ outb(CLRSCSIINT, CLRINT + base); scb = NULL; } - else if (status & SCSIRSTI) - { - PAUSE_SEQUENCER(p); - printk ("aic7xxx: Someone reset channel %c (SCSIINT).\n", channel); - /* - * Go through and abort all commands for the channel, but do not - * reset the channel again. - */ - aic7xxx_reset_channel (p, channel, SCB_LIST_NULL, FALSE); - } else if (status & SCSIPERR) { char *phase; @@ -2412,8 +3017,8 @@ * A parity error has occurred during a data * transfer phase. Flag it and continue. */ - printk("aic7xxx: Parity error during phase %s on target %d, " - "channel %d, lun %d.\n", phase, + printk(KERN_WARNING "scsi%d: Parity error during phase %s on target %d, " + "channel %d, lun %d.\n", p->host_no, phase, cmd->target, cmd->channel & 0x01, cmd->lun & 0x07); /* @@ -2424,16 +3029,16 @@ */ if (mesg_out != MSG_NOP) { - outb(mesg_out, MSG0 + base); - outb(1, MSG_LEN + base); - cmd->result = DID_PARITY << 16; + outb(mesg_out, MSG0 + base); + outb(1, MSG_LEN + base); + cmd->result = DID_PARITY << 16; } else { - /* - * Should we allow the target to make this decision for us? - */ - cmd->result = DID_RETRY_COMMAND << 16; + /* + * Should we allow the target to make this decision for us? + */ + cmd->result = DID_RETRY_COMMAND << 16; } aic7xxx_done(p, scb); } @@ -2443,11 +3048,6 @@ cmd = scb->cmd; - /* - * Hardware selection timer has expired. Turn - * off SCSI selection sequence. - */ - outb(ENRSELI, SCSISEQ + base); cmd->result = (DID_TIME_OUT << 16); /* * Clear an pending messages for the timed out @@ -2456,26 +3056,12 @@ ha_flags = inb(FLAGS + base); outb(0, MSG_LEN + base); aic7xxx_unbusy_target(scsi_id, channel, base); - - outb(0, SCBARRAY + base); - /* - * Shut off the offending interrupt sources, reset - * the sequencer address to zero and unpause it, - * then call the high-level SCSI completion routine. - * - * WARNING! This is a magic sequence! After many - * hours of guesswork, turning off the SCSI interrupts - * in CLRSINT? does NOT clear the SCSIINT bit in - * INTSTAT. By writing to the (undocumented, unused - * according to the AIC-7770 manual) third bit of - * CLRINT, you can clear INTSTAT. But, if you do it - * while the sequencer is paused, you get a BRKADRINT - * with an Illegal Host Address status, so the - * sequencer has to be restarted first. + * Stop the selection. */ + outb(0, SCSISEQ + base); + outb(0, SCB_CONTROL + base); outb(CLRSELTIMEO, CLRSINT1 + base); - outb(CLRSCSIINT, CLRINT + base); /* @@ -2483,15 +3069,11 @@ */ waiting = inb(WAITING_SCBH + base); outb(waiting, SCBPTR + base); - waiting = inb(SCB_NEXT_WAITING + base); + waiting = inb(SCB_NEXT + base); outb(waiting, WAITING_SCBH + base); RESTART_SEQUENCER(p); aic7xxx_done(p, scb); -#if 0 -printk("aic7xxx: SELTO SCB(%d) state(0x%x) cmd(0x%x).\n", - scb->position, scb->state, (unsigned int) scb->cmd); -#endif } else if (!(status & BUSFREE)) { @@ -2499,13 +3081,16 @@ * We don't know what's going on. Turn off the * interrupt source and try to continue. */ - printk("aic7xxx: SSTAT1(0x%x).\n", status); + printk(KERN_WARNING "aic7xxx: SSTAT1(0x%x).\n", status); outb(status, CLRSINT1 + base); UNPAUSE_SEQUENCER(p); outb(CLRSCSIINT, CLRINT + base); } } + if (run_aborted_queue) + aic7xxx_done_aborted_scbs(p); + if (intstat & CMDCMPLT) { int complete; @@ -2521,11 +3106,11 @@ scb = &(p->scb_array[complete]); if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL)) { - printk("aic7xxx: Warning - No command for SCB %d (CMDCMPLT).\n" - " QOUTCNT(%d) QINCNT(%d) SCB state(0x%x) cmd(0x%x) " - "pos(%d).\n", - complete, inb(QOUTCNT + base), inb(QINCNT + base), - scb->state, (unsigned int) scb->cmd, scb->position); + printk(KERN_WARNING "scsi%d: CMDCMPLT without command for SCB %d.\n" + " QOUTCNT %d, QINCNT %d, SCB state 0x%x, cmd 0x%x, " + "pos(%d).\n", p->host_no, complete, inb(QOUTCNT + base), + inb(QINCNT + base), scb->state, (unsigned int) scb->cmd, + scb->position); outb(CLRCMDINT, CLRINT + base); continue; } @@ -2538,30 +3123,17 @@ */ cmd->flags &= ASKED_FOR_SENSE; } -#if 0 - printk("aic7xxx: (complete) State(%d) cmd(0x%x) free(0x%x).\n", - scb->state, (unsigned int) scb->cmd, (unsigned int) p->free_scb); -#endif + p->device_status[TARGET_INDEX(cmd)].flags |= DEVICE_SUCCESS; /* - * Clear interrupt status before checking - * the output queue again. This eliminates - * a race condition whereby a command could - * complete between the queue poll and the - * interrupt clearing, so notification of the - * command being complete never made it back - * up to the kernel. + * Clear interrupt status before checking the output queue again. + * This eliminates a race condition whereby a command could + * complete between the queue poll and the interrupt clearing, + * so notification of the command being complete never made it + * back up to the kernel. */ outb(CLRCMDINT, CLRINT + base); aic7xxx_done(p, scb); -#if 0 - if (scb != &p->scb_array[scb->position]) - { - printk("aic7xxx: (complete) Address mismatch, pos(%d).\n", scb->position); - } - printk("aic7xxx: (complete) State(%d) cmd(0x%x) free(0x%x).\n", - scb->state, (unsigned int) scb->cmd, (unsigned int) p->free_scb); -#endif #ifdef AIC7XXX_PROC_STATS /* @@ -2607,6 +3179,67 @@ } while (inb(QOUTCNT + base) & p->qcntmask); } + aic7xxx_done_cmds_complete(p); + p->flags &= ~IN_ISR; + aic7xxx_run_waiting_queues(p); +} + +/*+F************************************************************************* + * Function: + * aic7xxx_select_queue_depth + * + * Description: + * Sets the queue depth for each SCSI device hanging off the input + * host adapter. We use a queue depth of 2 for devices that do not + * support tagged queueing. If AIC7XXX_CMDS_PER_LUN is defined, we + * use that for tagged queueing devices; otherwise we use our own + * algorithm for determining the queue depth based on the maximum + * SCBs for the controller. + *-F*************************************************************************/ +static void aic7xxx_select_queue_depth(struct Scsi_Host *host, + Scsi_Device *scsi_devs) +{ + Scsi_Device *device = scsi_devs; + int tq_depth = 2; + +#ifdef AIC7XXX_CMDS_PER_LUN + tq_depth = AIC7XXX_CMDS_PER_LUN; +#else + { + struct aic7xxx_host *p = (struct aic7xxx_host *) host->hostdata; + + if (p->maxhscbs <= 4) + { + tq_depth = 4; /* Not many SCBs to work with. */ + } + else + { + tq_depth = 8; + } + } +#endif + + for (device = scsi_devs; device != NULL; device = device->next) + { + if (device->host == host) + { + device->queue_depth = 2; +#ifdef AIC7XXX_TAGGED_QUEUEING + if (device->tagged_supported) + { + device->queue_depth = tq_depth; + if (device->tagged_queue == 0) + { + printk(KERN_INFO "scsi%d: Enabled tagged queuing for target %d, " + "channel %d, LUN %d, queue depth %d.\n", host->host_no, + device->id, device->channel, device->lun, device->queue_depth); + device->tagged_queue = 1; + device->current_tag = SCB_LIST_NULL; + } + } +#endif + } + } } /*+F************************************************************************* @@ -3043,6 +3676,9 @@ unsigned char sblkctl_reg; int base, i; +#ifdef AIC7XXX_PAGE_ENABLE + config->flags |= PAGE_ENABLED; +#endif base = config->base; switch (config->type) { @@ -3052,8 +3688,9 @@ /* * Check for Rev C or E boards. Rev E boards can supposedly have * more than 4 SCBs, while the Rev C boards are limited to 4 SCBs. - * Until we know how to access more than 4 SCBs for the Rev E chips, - * we limit them, along with the Rev C chips, to 4 SCBs. + * It's still not clear extactly what is different about the Rev E + * boards, but we think it allows 8 bit entries in the QOUTFIFO to + * support "paging" SCBs (more than 4 commands can be active at once). * * The Rev E boards have a read/write autoflush bit in the * SBLKCTL register, while in the Rev C boards it is read only. @@ -3063,15 +3700,18 @@ if (inb(SBLKCTL + base) == sblkctl_reg) { /* - * We detected a Rev E board. + * We detected a Rev E board, we allow paging on this board. */ - printk("aic7xxx: %s Rev E and subsequent.\n", + printk(KERN_INFO "aic7xxx: %s Rev E and subsequent.\n", board_names[config->type]); outb(sblkctl_reg ^ AUTOFLUSHDIS, SBLKCTL + base); } else { - printk("aic7xxx: %s Rev C and previous.\n", board_names[config->type]); + /* Do not allow paging. */ + config->flags &= ~PAGE_ENABLED; + printk(KERN_INFO "aic7xxx: %s Rev C and previous.\n", + board_names[config->type]); } break; @@ -3083,8 +3723,8 @@ * Walk the SCBs to determine how many there are. */ i = 1; - outb (0, SCBPTR + base); - outb (0, SCBARRAY + base); + outb(0, SCBPTR + base); + outb(0, SCBARRAY + base); while (i < AIC7XXX_MAXSCB) { @@ -3107,11 +3747,23 @@ outb(0, SCBPTR + base); outb(0, SCBARRAY + base); - config->maxscb = i; + config->maxhscbs = i; config->qcntmask |= i; + if ((config->flags & PAGE_ENABLED) && (config->maxhscbs < AIC7XXX_MAXSCB)) + { + config->maxscbs = AIC7XXX_MAXSCB; + } + else + { + config->flags &= ~PAGE_ENABLED; /* Disable paging if we have 255 SCBs!. */ + config->maxscbs = config->maxhscbs; + } - printk("aic7xxx: Using %d SCB's after checking for SCB memory.\n", - config->maxscb); + printk(KERN_INFO "aic7xxx: Memory check yields %d SCBs", config->maxhscbs); + if (config->flags & PAGE_ENABLED) + printk(", %d page-enabled SCBs.\n", config->maxscbs); + else + printk(", paging not enabled.\n"); } @@ -3127,11 +3779,13 @@ struct aic7xxx_host_config *config) { int i; - unsigned char sblkctl; + unsigned char sblkctl, flags = 0; int max_targets; - int found = 1, base; + int found = 1; + unsigned int sram, base; unsigned char target_settings; unsigned char scsi_conf, host_conf; + unsigned short ultraenable = 0; int have_seeprom = FALSE; struct Scsi_Host *host; struct aic7xxx_host *p; @@ -3142,31 +3796,40 @@ /* * Lock out other contenders for our i/o space. */ - request_region(MINREG + base, MAXREG - MINREG, "aic7xxx"); + request_region(base, MAXREG - MINREG, "aic7xxx"); switch (config->type) { case AIC_7770: case AIC_7771: /* - * For some 274x boards, we must clear the CHIPRST bit - * and pause the sequencer. For some reason, this makes - * the driver work. For 284x boards, we give it a - * CHIPRST just like the 294x boards. - * - * Use the BIOS settings to determine the interrupt - * trigger type (level or edge) and use this value - * for pausing and unpausing the sequencer. + * Use the boot-time option for the interrupt trigger type. If not + * supplied (-1), then we use BIOS settings to determine the interrupt + * trigger type (level or edge) and use this value for pausing and + * unpausing the sequencer. */ - config->unpause = (inb(HCNTRL + base) & IRQMS) | INTEN; + switch (aic7xxx_irq_trigger) + { + case 0: config->unpause = INTEN; /* Edge */ + break; + case 1: config->unpause = IRQMS | INTEN; /* Level */ + break; + case -1: + default: config->unpause = (inb(HCNTRL + base) & IRQMS) | INTEN; + break; + } config->pause = config->unpause | PAUSE; - config->extended = aic7xxx_extended; + /* + * For some 274x boards, we must clear the CHIPRST bit and pause + * the sequencer. For some reason, this makes the driver work. + * For 284x boards, we give it a CHIPRST just like the 294x boards. + */ outb(config->pause | CHIPRST, HCNTRL + base); aic7xxx_delay(1); if (inb(HCNTRL + base) & CHIPRST) { - printk("aic7xxx: Chip reset not cleared; clearing manually.\n"); + printk(KERN_INFO "aic7xxx: Chip reset not cleared; clearing manually.\n"); } outb(config->pause, HCNTRL + base); @@ -3179,7 +3842,7 @@ (inb(HA_274_BIOSCTRL + base) & BIOSMODE) == BIOSDISABLED) { config->bios = AIC_DISABLED; - config->use_defaults = TRUE; + config->flags |= USE_DEFAULTS; } else { @@ -3197,8 +3860,8 @@ /* * A reminder until this can be detected automatically. */ - printk("aic7xxx: Extended translation %sabled.\n", - config->extended ? "en" : "dis"); + printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n", + (config->flags & EXTENDED_TRANSLATION) ? "en" : "dis"); break; case AIC_284x: @@ -3209,11 +3872,10 @@ outb(config->pause, HCNTRL + base); config->parity = AIC_ENABLED; - config->extended = aic7xxx_extended; config->irq = inb(INTDEF + base) & 0x0F; host_conf = inb(HOSTCONF + base); - printk("aic7xxx: Reading SEEPROM..."); + printk(KERN_INFO "aic7xxx: Reading SEEPROM..."); have_seeprom = read_2840_seeprom(base, &sc); if (!have_seeprom) { @@ -3222,7 +3884,9 @@ else { printk("done.\n"); - config->extended = ((sc.bios_control & CF284XEXTEND) >> 5); + config->flags |= HAVE_SEEPROM; + if (sc.bios_control & CF284XEXTEND) + config->flags |= EXTENDED_TRANSLATION; if (!(sc.bios_control & CFBIOSEN)) { /* @@ -3256,10 +3920,23 @@ outb(config->bus_speed & DFTHRSH, BUSSPD + base); outb(config->busrtime, BUSTIME + base); - printk("aic7xxx: Extended translation %sabled.\n", - config->extended ? "en" : "dis"); + printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n", + (config->flags & EXTENDED_TRANSLATION) ? "en" : "dis"); break; + case AIC_7860: + case AIC_7880: + case AIC_7881: + case AIC_7882: + case AIC_7883: + case AIC_7884: + /* + * Remember if Ultra was enabled in case there is no SEEPROM. + * Fall through to the rest of the AIC_78xx code. + */ + if (inb(SXFRCTL0 + base) & ULTRAEN) + config->flags |= ULTRA_ENABLED; + case AIC_7850: case AIC_7855: case AIC_7870: @@ -3267,31 +3944,56 @@ case AIC_7872: case AIC_7873: case AIC_7874: - case AIC_7880: - case AIC_7881: - case AIC_7882: - case AIC_7883: - case AIC_7884: + /* + * Grab the SCSI ID before chip reset in case there is no SEEPROM. + */ + config->scsi_id = inb(SCSIID + base) & OID; outb(CHIPRST, HCNTRL + base); config->unpause = UNPAUSE_294X; config->pause = config->unpause | PAUSE; aic7xxx_delay(1); outb(config->pause, HCNTRL + base); - config->extended = aic7xxx_extended; - config->scsi_id = 7; config->parity = AIC_ENABLED; - printk("aic7xxx: Reading SEEPROM..."); + printk(KERN_INFO "aic7xxx: Reading SEEPROM..."); have_seeprom = read_seeprom(base, config->chan_num * (sizeof(sc) / 2), &sc); if (!have_seeprom) { - printk("\naic7xxx: Unable to read SEEPROM; " - "using leftover BIOS values.\n"); + for (sram = base + TARG_SCRATCH; sram < base + 0x60; sram++) + { + if (inb(sram) != 0x00) + break; + } + if (sram == base + TARG_SCRATCH) + { + for (sram = base + TARG_SCRATCH; sram < base + 0x60; sram++) + { + if (inb(sram) != 0xFF) + break; + } + } + if ((sram != base + 0x60) && (config->scsi_id != 0)) + { + config->flags &= ~USE_DEFAULTS; + printk("\naic7xxx: Unable to read SEEPROM; " + "using leftover BIOS values.\n"); + } + else + { + printk("\n"); + printk(KERN_INFO "aic7xxx: Unable to read SEEPROM; using default " + "settings.\n"); + config->flags |= USE_DEFAULTS; + config->flags &= ~ULTRA_ENABLED; + config->scsi_id = 7; + } + scsi_conf = ENSPCHK | RESET_SCSI; } else { printk("done.\n"); + config->flags |= HAVE_SEEPROM; if (!(sc.bios_control & CFBIOSEN)) { /* @@ -3300,10 +4002,17 @@ * AIC-7770 case. */ config->bios = AIC_DISABLED; + scsi_conf = ENSPCHK | RESET_SCSI; } else { - config->extended = ((sc.bios_control & CFEXTEND) >> 7); + scsi_conf = 0; + if (sc.adapter_control & CFRESETB) + scsi_conf |= RESET_SCSI; + if (sc.adapter_control & CFSPARITY) + scsi_conf |= ENSPCHK; + if (sc.bios_control & CFEXTEND) + config->flags |= EXTENDED_TRANSLATION; config->scsi_id = (sc.brtime_id & CFSCSIID); config->parity = (sc.adapter_control & CFSPARITY) ? AIC_ENABLED : AIC_DISABLED; @@ -3312,32 +4021,19 @@ config->high_term = (sc.adapter_control & CFWSTERM) ? AIC_ENABLED : AIC_DISABLED; config->busrtime = ((sc.brtime_id & CFBRTIME) >> 8); - if (((config->type == AIC_7880) || (config->type == AIC_7882) || - (config->type == AIC_7883) || (config->type == AIC_7884)) && - (sc.adapter_control & CFULTRAEN)) + if (((config->type == AIC_7880) || (config->type == AIC_7881) || + (config->type == AIC_7882) || (config->type == AIC_7883) || + (config->type == AIC_7884)) && (sc.adapter_control & CFULTRAEN)) { - printk ("aic7xxx: Enabling support for Ultra SCSI speed.\n"); - config->ultra_enabled = TRUE; + printk(KERN_INFO "aic7xxx: Enabling support for Ultra SCSI " + "speed.\n"); + config->flags |= ULTRA_ENABLED; } } } - /* - * XXX - force data fifo threshold to 100%. Why does this - * need to be done? - * - * We don't know where this is set in the SEEPROM or by the BIOS, - * so we default it to 100%. - */ + outb(scsi_conf | (config->scsi_id & 0x07), SCSICONF + base); config->bus_speed = DFTHRSH_100; - scsi_conf = config->scsi_id | config->bus_speed; -#if 0 - if (config->parity == AIC_ENABLED) - { - scsi_conf |= ENSPCHK; - } -#endif - outb(scsi_conf, SCSICONF + base); outb(config->bus_speed, DSPCISTATUS + base); /* @@ -3345,12 +4041,12 @@ */ outb(config->scsi_id, SCSICONF + base + 1); - printk("aic7xxx: Extended translation %sabled.\n", - config->extended ? "en" : "dis"); + printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n", + (config->flags & EXTENDED_TRANSLATION) ? "en" : "dis"); break; default: - panic("aic7xxx: (aic7xxx_register) Internal error.\n"); + panic(KERN_WARNING "aic7xxx: (aic7xxx_register) Internal error.\n"); } detect_maxscb(config); @@ -3359,11 +4055,11 @@ { if (config->pause & IRQMS) { - printk("aic7xxx: Using level sensitive interrupts.\n"); + printk(KERN_INFO "aic7xxx: Using level sensitive interrupts.\n"); } else { - printk("aic7xxx: Using edge triggered interrupts.\n"); + printk(KERN_INFO "aic7xxx: Using edge triggered interrupts.\n"); } } @@ -3372,12 +4068,15 @@ * register in the sequencer for twin and wide bus cards. */ sblkctl = inb(SBLKCTL + base); + if (config->flags & PAGE_ENABLED) + flags = PAGESCBS; + switch (sblkctl & SELBUS_MASK) { case SELNARROW: /* narrow/normal bus */ config->scsi_id = inb(SCSICONF + base) & 0x07; config->bus_type = AIC_SINGLE; - outb(SINGLE_BUS, FLAGS + base); + outb(flags | SINGLE_BUS, FLAGS + base); break; case SELWIDE: /* Wide bus */ @@ -3385,7 +4084,7 @@ config->bus_type = AIC_WIDE; printk("aic7xxx: Enabling wide channel of %s-Wide.\n", board_names[config->type]); - outb(WIDE_BUS, FLAGS + base); + outb(flags | WIDE_BUS, FLAGS + base); break; case SELBUSB: /* Twin bus */ @@ -3393,19 +4092,19 @@ #ifdef AIC7XXX_TWIN_SUPPORT config->scsi_id_b = inb(SCSICONF + base + 1) & 0x07; config->bus_type = AIC_TWIN; - printk("aic7xxx: Enabled channel B of %s-Twin.\n", + printk(KERN_INFO "aic7xxx: Enabled channel B of %s-Twin.\n", board_names[config->type]); - outb(TWIN_BUS, FLAGS + base); + outb(flags | TWIN_BUS, FLAGS + base); #else config->bus_type = AIC_SINGLE; - printk("aic7xxx: Channel B of %s-Twin will be ignored.\n", + printk(KERN_INFO "aic7xxx: Channel B of %s-Twin will be ignored.\n", board_names[config->type]); - outb(0, FLAGS + base); + outb(flags, FLAGS + base); #endif break; default: - printk("aic7xxx: Unsupported type 0x%x, please " + printk(KERN_WARNING "aic7xxx: Unsupported type 0x%x, please " "mail deang@teleport.com\n", inb(SBLKCTL + base)); outb(0, FLAGS + base); return (0); @@ -3430,26 +4129,12 @@ */ if ((config->chip_type == AIC_777x) && ((config->irq < 9) || (config->irq > 15))) { - printk("aic7xxx: Host adapter uses unsupported IRQ level, ignoring.\n"); + printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ level, " + "ignoring.\n"); return (0); } /* - * Check the IRQ to see if it is shared by another aic7xxx - * controller. If it is and sharing of IRQs is not defined, - * then return 0 hosts found. If sharing of IRQs is allowed - * or the IRQ is not shared by another host adapter, then - * proceed. - */ -#ifndef AIC7XXX_SHARE_IRQS - if (aic7xxx_boards[config->irq] != NULL) - { - printk("aic7xxx: Sharing of IRQ's is not configured.\n"); - return (0); - } -#endif - - /* * Print out debugging information before re-enabling * the card - a lot of registers on it can't be read * when the sequencer is active. @@ -3469,8 +4154,8 @@ if (SG_STRUCT_CHECK(sg)) { - printk("aic7xxx: Warning - Kernel scatter-gather structures changed, " - "disabling it.\n"); + printk(KERN_WARNING "aic7xxx: Warning - Kernel scatter-gather structures " + "changed, disabling it.\n"); template->sg_tablesize = SG_NONE; } } @@ -3484,9 +4169,13 @@ * information when an IRQ is triggered. */ host = scsi_register(template, sizeof(struct aic7xxx_host)); - host->can_queue = config->maxscb; - host->cmd_per_lun = AIC7XXX_CMDS_PER_LUN; + host->can_queue = config->maxscbs; + host->cmd_per_lun = 2; + host->select_queue_depths = aic7xxx_select_queue_depth; host->this_id = config->scsi_id; + host->io_port = config->base; + host->n_io_port = 0xFF; + host->base = (char *)config->mbase; host->irq = config->irq; if (config->bus_type == AIC_WIDE) { @@ -3500,28 +4189,37 @@ p = (struct aic7xxx_host *) host->hostdata; p->host = host; + p->host_no = (int)host->host_no; p->isr_count = 0; - p->a_scanned = FALSE; - p->b_scanned = FALSE; p->base = base; - p->maxscb = config->maxscb; + p->maxscbs = config->maxscbs; + p->maxhscbs = config->maxhscbs; p->qcntmask = config->qcntmask; - p->numscb = 0; - p->extended = config->extended; + p->numscbs = 0; + p->mbase = (char *)config->mbase; p->type = config->type; p->chip_type = config->chip_type; - p->ultra_enabled = config->ultra_enabled; + p->flags = config->flags; p->chan_num = config->chan_num; p->bus_type = config->bus_type; - p->have_seeprom = have_seeprom; p->seeprom = sc; - p->free_scb = NULL; - p->aborted_scb = NULL; p->next = NULL; + p->completeq.head = NULL; + p->completeq.tail = NULL; + scbq_init(&p->free_scbs); + scbq_init(&p->page_scbs); + scbq_init(&p->waiting_scbs); + scbq_init(&p->assigned_scbs); p->unpause = config->unpause; p->pause = config->pause; + for (i = 0; i <= 15; i++) + { + p->device_status[i].commands_sent = 0; + p->device_status[i].flags = 0; + p->device_status[i].last_reset = 0; + } if (aic7xxx_boards[config->irq] == NULL) { /* @@ -3536,9 +4234,11 @@ /* * Register IRQ with the kernel. */ - if (request_irq(config->irq, aic7xxx_isr, SA_INTERRUPT, "aic7xxx", NULL)) + if (request_irq(config->irq, aic7xxx_isr, SA_INTERRUPT | SA_SHIRQ, + "aic7xxx", NULL)) { - printk("aic7xxx: Couldn't register IRQ %d, ignoring.\n", config->irq); + printk(KERN_WARNING "aic7xxx: Couldn't register IRQ %d, ignoring.\n", + config->irq); aic7xxx_boards[config->irq] = NULL; return (0); } @@ -3561,7 +4261,7 @@ * but then your mailing address is dynamically assigned * so no one can find you anyway :-) */ - printk("aic7xxx: Downloading sequencer code..."); + printk(KERN_INFO "aic7xxx: Downloading sequencer code..."); aic7xxx_loadseq(base); /* @@ -3589,8 +4289,12 @@ outb(config->scsi_id_b, SCSIID + base); scsi_conf = inb(SCSICONF + base + 1) & (ENSPCHK | STIMESEL); outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1 + base); +#if 1 + outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1 + base); +#else outb(ENSELTIMO, SIMODE1 + base); - if (p->ultra_enabled) +#endif + if (p->flags & ULTRA_ENABLED) { outb(DFON | SPIOEN | ULTRAEN, SXFRCTL0 + base); } @@ -3607,8 +4311,12 @@ outb(config->scsi_id, SCSIID + base); scsi_conf = inb(SCSICONF + base) & (ENSPCHK | STIMESEL); outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1 + base); +#if 1 + outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1 + base); +#else outb(ENSELTIMO, SIMODE1 + base); - if (p->ultra_enabled) +#endif + if (p->flags & ULTRA_ENABLED) { outb(DFON | SPIOEN | ULTRAEN, SXFRCTL0 + base); } @@ -3649,7 +4357,7 @@ { if (config->bios == AIC_DISABLED) { - printk("aic7xxx : Host adapter BIOS disabled. Using default SCSI " + printk(KERN_INFO "aic7xxx : Host adapter BIOS disabled. Using default SCSI " "device parameters.\n"); p->discenable = 0xFFFF; } @@ -3662,29 +4370,29 @@ for (i = 0; i < max_targets; i++) { - if (have_seeprom) + if (config->flags & USE_DEFAULTS) { - target_settings = ((sc.device_flags[i] & CFXFER) << 4); - if (sc.device_flags[i] & CFSYNCH) + target_settings = 0; /* 10 MHz */ + p->needsdtr_copy |= (0x01 << i); + p->needwdtr_copy |= (0x01 << i); + } + else + { + if (have_seeprom) { - p->needsdtr_copy |= (0x01 << i); - } - if (sc.device_flags[i] & CFWIDEB) - { - p->needwdtr_copy |= (0x01 << i); - } - if (sc.device_flags[i] & CFDISC) - { - p->discenable |= (0x01 << i); - } - } - else - { - if (config->use_defaults) - { - target_settings = 0; /* 10 MHz */ - p->needsdtr_copy |= (0x01 << i); - p->needwdtr_copy |= (0x01 << i); + target_settings = ((sc.device_flags[i] & CFXFER) << 4); + if (sc.device_flags[i] & CFSYNCH) + { + p->needsdtr_copy |= (0x01 << i); + } + if (sc.device_flags[i] & CFWIDEB) + { + p->needwdtr_copy |= (0x01 << i); + } + if (sc.device_flags[i] & CFDISC) + { + p->discenable |= (0x01 << i); + } } else { @@ -3703,6 +4411,22 @@ target_settings &= 0x7F; } } + if (p->flags & ULTRA_ENABLED) + { + switch (target_settings & 0x70) + { + case 0x00: + case 0x10: + case 0x20: + ultraenable |= (0x01 << i); + break; + case 0x40: + target_settings &= ~(0x70); + break; + default: + break; + } + } } outb(target_settings, (TARG_SCRATCH + base + i)); } @@ -3718,26 +4442,28 @@ } p->needsdtr = p->needsdtr_copy; p->needwdtr = p->needwdtr_copy; + p->orderedtag = 0; #if 0 printk("NeedSdtr = 0x%x, 0x%x\n", p->needsdtr_copy, p->needsdtr); printk("NeedWdtr = 0x%x, 0x%x\n", p->needwdtr_copy, p->needwdtr); #endif + outb(ultraenable & 0xFF, ULTRA_ENB + base); + outb((ultraenable >> 8) & 0xFF, ULTRA_ENB + base + 1); /* - * For reconnecting targets, the sequencer code needs to - * know how many SCBs it has to search through. + * Set the number of available SCBs. */ - outb(config->maxscb, SCBCOUNT + base); + outb(config->maxhscbs, SCBCOUNT + base); /* - * 2s compliment of SCBCOUNT + * 2s compliment of maximum tag value. */ - i = p->maxscb; + i = p->maxscbs; outb(-i & 0xFF, COMP_SCBCOUNT + base); /* * Set the QCNT (queue count) mask to deal with broken aic7850s that - * sporadically get garbage in the upper bits of their QCNT registers. + * sporatically get garbage in the upper bits of their QCNT registers. */ outb(config->qcntmask, QCNTMASK + base); @@ -3748,9 +4474,10 @@ outb(0, ACTIVE_B + base); /* - * We don't have any waiting selections + * We don't have any waiting selections or disconnected SCBs. */ outb(SCB_LIST_NULL, WAITING_SCBH + base); + outb(SCB_LIST_NULL, DISCONNECTED_SCBH + base); /* * Message out buffer starts empty @@ -3769,7 +4496,6 @@ * Some devices need a long time to "settle" after a SCSI * bus reset. */ - if (!aic7xxx_no_reset) { printk("aic7xxx: Resetting the SCSI bus..."); @@ -3784,13 +4510,11 @@ udelay(1000); outb(0, SCSISEQ + base); - /* - * Ensure we don't get a RSTI interrupt from this. - */ + /* Ensure we don't get a RSTI interrupt from this. */ outb(CLRSCSIRSTI, CLRSINT1 + base); outb(CLRSCSIINT, CLRINT + base); - /* + /* * Select Channel A. */ outb((sblkctl & ~SELBUS_MASK) | SELNARROW, SBLKCTL + base); @@ -3800,9 +4524,7 @@ udelay(1000); outb(0, SCSISEQ + base); - /* - * Ensure we don't get a RSTI interrupt from this. - */ + /* Ensure we don't get a RSTI interrupt from this. */ outb(CLRSCSIRSTI, CLRSINT1 + base); outb(CLRSCSIINT, CLRINT + base); @@ -3862,7 +4584,7 @@ { base = SLOTBASE(slot) + MINREG; - if (check_region(MINREG + base, MAXREG - MINREG)) + if (check_region(base, MAXREG - MINREG)) { /* * Some other driver has staked a @@ -3886,14 +4608,16 @@ */ config.chip_type = AIC_777x; config.base = base; + config.mbase = 0; config.irq = irq; config.parity = AIC_ENABLED; config.low_term = AIC_UNKNOWN; config.high_term = AIC_UNKNOWN; - config.ultra_enabled = FALSE; - config.extended = aic7xxx_extended; + config.flags = 0; + if (aic7xxx_extended) + config.flags |= EXTENDED_TRANSLATION; config.bus_speed = DFTHRSH_100; - config.busrtime = BOFF_60BCLKS; + config.busrtime = BOFF; found += aic7xxx_register(template, &config); /* @@ -3918,6 +4642,7 @@ } const aic7xxx_pci_devices[] = { {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7850, AIC_7850, AIC_785x}, {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AIC_7855, AIC_785x}, + {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AIC_7860, AIC_785x}, {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7870, AIC_7870, AIC_787x}, {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7871, AIC_7871, AIC_787x}, {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7872, AIC_7872, AIC_787x}, @@ -3932,7 +4657,7 @@ int error; int done = 0; - unsigned int io_port; + unsigned int iobase, mbase; unsigned short index = 0; unsigned char pci_bus, pci_device_fn; unsigned int csize_lattime; @@ -3949,6 +4674,7 @@ aic7xxx_pci_devices[i].device_id, index, &pci_bus, &pci_device_fn)) { + index = 0; done = TRUE; } else /* Found an Adaptec PCI device. */ @@ -3957,34 +4683,31 @@ config.chip_type = aic7xxx_pci_devices[i].chip_type; config.chan_num = 0; config.bios = AIC_ENABLED; /* Assume bios is enabled. */ - config.use_defaults = FALSE; + config.flags = 0; config.busrtime = 40; switch (config.type) { case AIC_7850: case AIC_7855: + case AIC_7860: config.bios = AIC_DISABLED; - config.use_defaults = TRUE; + config.flags |= USE_DEFAULTS; config.bus_speed = DFTHRSH_100; break; case AIC_7872: /* 3940 */ case AIC_7882: /* 3940-Ultra */ - config.chan_num = number_of_39xxs & 0x01; /* Has 2 controllers */ - number_of_39xxs++; - if (number_of_39xxs == 2) - { - number_of_39xxs = 0; /* To be consistent with 3985. */ - } + config.chan_num = number_of_3940s & 0x1; /* Has 2 controllers */ + number_of_3940s++; break; case AIC_7873: /* 3985 */ case AIC_7883: /* 3985-Ultra */ - config.chan_num = number_of_39xxs & 0x03; /* Has 3 controllers */ - number_of_39xxs++; - if (number_of_39xxs == 3) + config.chan_num = number_of_3985s & 0x3; /* Has 3 controllers */ + number_of_3985s++; + if (number_of_3985s == 3) { - number_of_39xxs = 0; + number_of_3985s = 0; } break; @@ -3996,43 +4719,32 @@ * Read sundry information from PCI BIOS. */ error = pcibios_read_config_dword(pci_bus, pci_device_fn, - PCI_BASE_ADDRESS_0, &io_port); + PCI_BASE_ADDRESS_0, &iobase); error += pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_INTERRUPT_LINE, &irq); + error += pcibios_read_config_dword(pci_bus, pci_device_fn, + PCI_BASE_ADDRESS_1, &mbase); /* - * Ensure that we are using good values for the PCI burst size - * and latency timer. + * The first bit of PCI_BASE_ADDRESS_0 is always set, so + * we mask it off. + */ + iobase &= PCI_BASE_ADDRESS_IO_MASK; + + /* + * Read the PCI burst size and latency timer. */ error += pcibios_read_config_dword(pci_bus, pci_device_fn, CSIZE_LATTIME, &csize_lattime); - if ((csize_lattime & CACHESIZE) == 0) - { - /* - * Default to 8DWDs - what's the PCI define for this? - */ - csize_lattime |= 8; - } - - if ((csize_lattime & LATTIME) == 0) - { - /* - * Default to 64 PCLKS (is this a good value?) - * This may also be available in the SEEPROM?? - */ - csize_lattime |= (64 << 8); - } - pcibios_write_config_dword(pci_bus, pci_device_fn, - CSIZE_LATTIME, csize_lattime); - printk("aic7xxx: BurstLen = %d DWDs, Latency Timer = %d PCLKS\n", - (int) (csize_lattime & CACHESIZE), - (csize_lattime >> 8) & 0x000000ff); + printk(KERN_INFO "aic7xxx: BurstLen = %d DWDs, Latency Timer = %d " + "PCLKS\n", (int) (csize_lattime & CACHESIZE), + (csize_lattime >> 8) & 0x000000ff); error += pcibios_read_config_dword(pci_bus, pci_device_fn, CLASS_PROGIF_REVID, &class_revid); if ((class_revid & DEVREVID) < 3) { - printk("aic7xxx: %s Rev %c.\n", board_names[config.type], + printk(KERN_INFO "aic7xxx: %s Rev %c.\n", board_names[config.type], rev_id[class_revid & DEVREVID]); } @@ -4044,13 +4756,7 @@ error); } - printk("aic7xxx: devconfig = 0x%x.\n", devconfig); - - /* - * The first bit of PCI_BASE_ADDRESS_0 is always set, so - * we mask it off. - */ - base = io_port & 0xFFFFFFFE; + printk(KERN_INFO "aic7xxx: devconfig = 0x%x.\n", devconfig); /* * I don't think we need to bother with allowing @@ -4059,13 +4765,14 @@ */ aic7xxx_spurious_count = 1; - config.base = base; + config.base = iobase; + config.mbase = mbase; config.irq = irq; config.parity = AIC_ENABLED; config.low_term = AIC_UNKNOWN; config.high_term = AIC_UNKNOWN; - config.extended = aic7xxx_extended; - config.ultra_enabled = FALSE; + if (aic7xxx_extended) + config.flags |= EXTENDED_TRANSLATION; if (devconfig & RAMPSM) { /* @@ -4084,7 +4791,8 @@ * sixteen bits of the register are R/O anyway, so it shouldn't * affect RAMPSM either way. */ - printk ("aic7xxx: External RAM detected. Enabling RAM access.\n"); + printk(KERN_INFO "aic7xxx: External RAM detected; enabling RAM " + "access.\n"); devconfig &= ~(RAMPSM | SCBRAMSEL); pcibios_write_config_dword(pci_bus, pci_device_fn, DEVCONFIG, devconfig); @@ -4123,26 +4831,32 @@ unsigned short mask; struct scatterlist *sg; + mask = (0x01 << TARGET_INDEX(cmd)); /* * Setup the control byte if we need negotiation and have not * already requested it. */ #ifdef AIC7XXX_TAGGED_QUEUEING - if (cmd->device->tagged_supported) + if (cmd->device->tagged_queue) { - if (cmd->device->tagged_queue == 0) + cmd->tag = scb->tag; + cmd->device->current_tag = scb->tag; + scb->control |= TAG_ENB; + p->device_status[TARGET_INDEX(cmd)].commands_sent++; + if (p->device_status[TARGET_INDEX(cmd)].commands_sent == 200) { - printk("aic7xxx: Enabling tagged queuing for target %d, " - "channel %d.\n", cmd->target, cmd->channel); - cmd->device->tagged_queue = 1; - cmd->device->current_tag = 1; /* enable tagging */ + scb->control |= 0x02; + p->device_status[TARGET_INDEX(cmd)].commands_sent = 0; } - cmd->tag = cmd->device->current_tag; - cmd->device->current_tag++; - scb->control |= TAG_ENB; +#if 0 + if (p->orderedtag & mask) + { + scb->control |= 0x02; + p->orderedtag = p->orderedtag & ~mask; + } +#endif } #endif - mask = (0x01 << (cmd->target | (cmd->channel << 3))); if (p->discenable & mask) { scb->control |= DISCENB; @@ -4247,23 +4961,24 @@ long flags; struct aic7xxx_host *p; struct aic7xxx_scb *scb; + u_char curscb; p = (struct aic7xxx_host *) cmd->host->hostdata; /* * Check to see if channel was scanned. */ - if (!p->a_scanned && (cmd->channel == 0)) + if (!(p->flags & A_SCANNED) && (cmd->channel == 0)) { - printk("aic7xxx: Scanning channel A for devices.\n"); - p->a_scanned = TRUE; + printk(KERN_INFO "scsi%d: Scanning channel A for devices.\n", p->host_no); + p->flags |= A_SCANNED; } else { - if (!p->b_scanned && (cmd->channel == 1)) + if (!(p->flags & B_SCANNED) && (cmd->channel == 1)) { - printk("aic7xxx: Scanning channel B for devices.\n"); - p->b_scanned = TRUE; + printk(KERN_INFO "scsi%d: Scanning channel B for devices.\n", p->host_no); + p->flags |= B_SCANNED; } } @@ -4283,109 +4998,98 @@ save_flags(flags); cli(); - /* - * Find a free slot in the SCB array to load this command - * into. Since can_queue is set to the maximum number of - * SCBs for the card, we should always find one. - * - * First try to find an scb in the free list. If there are - * none in the free list, then check the current number of - * of scbs and take an unused one from the scb array. - */ - scb = p->free_scb; - if (scb != NULL) - { /* found one in the free list */ - p->free_scb = scb->next; /* remove and update head of list */ - /* - * Warning! For some unknown reason, the scb at the head - * of the free list is not the same address that it should - * be. That's why we set the scb pointer taken by the - * position in the array. The scb at the head of the list - * should match this address, but it doesn't. - */ - scb = &(p->scb_array[scb->position]); - scb->control = 0; - scb->state = SCB_ACTIVE; + scb = aic7xxx_allocate_scb(p); + if (scb == NULL) + { + panic("aic7xxx: (aic7xxx_free) Couldn't find a free SCB.\n"); } else { - if (p->numscb >= p->maxscb) - { - panic("aic7xxx: (aic7xxx_queue) Couldn't find a free SCB.\n"); - } - else - { - /* - * Initialize the scb within the scb array. The - * position within the array is the position on - * the board that it will be loaded. - */ - scb = &(p->scb_array[p->numscb]); - memset(scb, 0, sizeof(*scb)); - - scb->position = p->numscb; - p->numscb++; - scb->state = SCB_ACTIVE; - } - } - - scb->cmd = cmd; - aic7xxx_position(cmd) = scb->position; + scb->cmd = cmd; + aic7xxx_position(cmd) = scb->tag; #if 0 - debug_scb(scb); + debug_scb(scb); #endif; - /* - * Construct the SCB beforehand, so the sequencer is - * paused a minimal amount of time. - */ - aic7xxx_buildscb(p, cmd, scb); + /* + * Construct the SCB beforehand, so the sequencer is + * paused a minimal amount of time. + */ + aic7xxx_buildscb(p, cmd, scb); #if 0 - if (scb != &p->scb_array[scb->position]) - { - printk("aic7xxx: (queue) Address of SCB by position does not match SCB " - "address.\n"); - } - printk("aic7xxx: (queue) SCB pos(%d) cmdptr(0x%x) state(%d) freescb(0x%x)\n", - scb->position, (unsigned int) scb->cmd, - scb->state, (unsigned int) p->free_scb); + if (scb != &p->scb_array[scb->position]) + { + printk("aic7xxx: (queue) Address of SCB by position does not match SCB " + "address.\n"); + } + printk("aic7xxx: (queue) SCB pos(%d) cmdptr(0x%x) state(%d) freescb(0x%x)\n", + scb->position, (unsigned int) scb->cmd, + scb->state, (unsigned int) p->free_scb); #endif - /* - * Make sure the Scsi_Cmnd pointer is saved, the struct it points to - * is set up properly, and the parity error flag is reset, then send - * the SCB to the sequencer and watch the fun begin. - */ - cmd->scsi_done = fn; - aic7xxx_error(cmd) = DID_OK; - aic7xxx_status(cmd) = 0; - cmd->result = 0; - memset(&cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); + /* + * Make sure the Scsi_Cmnd pointer is saved, the struct it points to + * is set up properly, and the parity error flag is reset, then send + * the SCB to the sequencer and watch the fun begin. + */ + cmd->scsi_done = fn; + aic7xxx_error(cmd) = DID_OK; + aic7xxx_status(cmd) = 0; + cmd->result = 0; + cmd->host_scribble = NULL; + memset(&cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); - /* - * Pause the sequencer so we can play with its registers - - * wait for it to acknowledge the pause. - * - * XXX - should the interrupts be left on while doing this? - */ - PAUSE_SEQUENCER(p); + if (scb->position != SCB_LIST_NULL) + { + /* We've got a valid slot, yeah! */ + if (p->flags & IN_ISR) + { + scbq_insert_tail(&p->assigned_scbs, scb); + scb->state |= SCB_ASSIGNEDQ; + } + else + { + /* + * Pause the sequencer so we can play with its registers - + * wait for it to acknowledge the pause. + * + * XXX - should the interrupts be left on while doing this? + */ + PAUSE_SEQUENCER(p); - /* - * Save the SCB pointer and put our own pointer in - this - * selects one of the four banks of SCB registers. Load - * the SCB, then write its pointer into the queue in FIFO - * and restore the saved SCB pointer. - */ - aic7xxx_putscb(p, scb); - outb(scb->position, QINFIFO + p->base); + /* + * Save the SCB pointer and put our own pointer in - this + * selects one of the four banks of SCB registers. Load + * the SCB, then write its pointer into the queue in FIFO + * and restore the saved SCB pointer. + */ + curscb = inb(SCBPTR + p->base); + outb(scb->position, SCBPTR + p->base); + aic7xxx_putscb(p, scb); + outb(curscb, SCBPTR + p->base); + outb(scb->position, QINFIFO + p->base); + scb->state |= SCB_ACTIVE; + + UNPAUSE_SEQUENCER(p); + } + } + else + { + scb->state |= SCB_WAITINGQ; + scbq_insert_tail(&p->waiting_scbs, scb); + if (!(p->flags & IN_ISR)) + { + aic7xxx_run_waiting_queues(p); + } + } - UNPAUSE_SEQUENCER(p); #if 0 - printk("aic7xxx: (queue) After - cmd(0x%lx) scb->cmd(0x%lx) pos(%d).\n", - (long) cmd, (long) scb->cmd, scb->position); + printk("aic7xxx: (queue) After - cmd(0x%lx) scb->cmd(0x%lx) pos(%d).\n", + (long) cmd, (long) scb->cmd, scb->position); #endif; - restore_flags(flags); + restore_flags(flags); + } return (0); } @@ -4400,201 +5104,208 @@ * aborted, then we will reset the channel and have all devices renegotiate. * Returns an enumerated type that indicates the status of the operation. *-F*************************************************************************/ -static aha_abort_reset_type -aic7xxx_abort_reset(Scsi_Cmnd *cmd, unsigned char errcode) +static int +aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd) { struct aic7xxx_scb *scb; - struct aic7xxx_host *p; long flags; unsigned char bus_state; - aha_abort_reset_type scb_status = ABORT_RESET_SUCCESS; - int base, found; + int base, result = -1; char channel; - p = (struct aic7xxx_host *) cmd->host->hostdata; scb = &(p->scb_array[aic7xxx_position(cmd)]); base = p->base; - channel = scb->target_channel_lun & SELBUSB ? 'B': 'A'; - - save_flags(flags); - cli(); - if (scb->state & SCB_ACTIVE) + channel = scb->target_channel_lun & SELBUSB ? 'B': 'A'; + if ((cmd == scb->cmd) && (scb->state & SCB_IN_PROGRESS)) { - /* - * Ensure that the card doesn't do anything - * behind our back. - */ - PAUSE_SEQUENCER(p); - printk ("aic7xxx: (abort_reset) scb state 0x%x, ", scb->state); - bus_state = inb(LASTPHASE + p->base); - - switch (bus_state) - { - case P_DATAOUT: - printk ("Data-Out phase, "); - break; - case P_DATAIN: - printk ("Data-In phase, "); - break; - case P_COMMAND: - printk ("Command phase, "); - break; - case P_MESGOUT: - printk ("Message-Out phase, "); - break; - case P_STATUS: - printk ("Status phase, "); - break; - case P_MESGIN: - printk ("Message-In phase, "); - break; - default: - printk ("while idle, LASTPHASE = 0x%x, ", bus_state); - /* - * We're not in a valid phase, so assume we're idle. - */ - bus_state = 0; - break; - } - printk ("SCSISIGI = 0x%x\n", inb (p->base + SCSISIGI)); + save_flags(flags); + cli(); - /* - * First, determine if we want to do a bus reset or simply a bus device - * reset. If this is the first time that a transaction has timed out, - * just schedule a bus device reset. Otherwise, we reset the bus and - * abort all pending I/Os on that bus. - */ - if (scb->state & SCB_ABORTED) + if (scb->state & SCB_IN_PROGRESS) { /* - * Been down this road before. Do a full bus reset. + * Ensure that the card doesn't do anything + * behind our back. */ - found = aic7xxx_reset_channel(p, channel, scb->position, TRUE); - } - else - { - unsigned char active_scb, control; - struct aic7xxx_scb *active_scbp; + PAUSE_SEQUENCER(p); - /* - * Send a Bus Device Reset Message: - * The target we select to send the message to may be entirely - * different than the target pointed to by the scb that timed - * out. If the command is in the QINFIFO or the waiting for - * selection list, it's not tying up the bus and isn't responsible - * for the delay so we pick off the active command which should - * be the SCB selected by SCBPTR. If it's disconnected or active, - * we device reset the target scbp points to. Although it may - * be that this target is not responsible for the delay, it may - * also be that we're timing out on a command that just takes - * too much time, so we try the bus device reset there first. - */ - active_scb = inb(SCBPTR + base); - active_scbp = &(p->scb_array[active_scb]); - control = inb(SCB_CONTROL + base); + printk(KERN_WARNING "aic7xxx: (abort_reset) scb state 0x%x, ", scb->state); + bus_state = inb(LASTPHASE + p->base); + + switch (bus_state) + { + case P_DATAOUT: + printk("Data-Out phase, "); + break; + case P_DATAIN: + printk("Data-In phase, "); + break; + case P_COMMAND: + printk("Command phase, "); + break; + case P_MESGOUT: + printk("Message-Out phase, "); + break; + case P_STATUS: + printk("Status phase, "); + break; + case P_MESGIN: + printk("Message-In phase, "); + break; + default: + printk("while idle, LASTPHASE = 0x%x, ", bus_state); + /* + * We're not in a valid phase, so assume we're idle. + */ + bus_state = 0; + break; + } + printk("SCSISIGI = 0x%x\n", inb(p->base + SCSISIGI)); /* - * Test to see if scbp is disconnected + * First, determine if we want to do a bus reset or simply a bus device + * reset. If this is the first time that a transaction has timed out + * and the SCB is not paged out, just schedule a bus device reset. + * Otherwise, we reset the bus and abort all pending I/Os on that bus. */ - outb(scb->position, SCBPTR + base); - if (inb(SCB_CONTROL + base) & DISCONNECTED) + if (!(scb->state & (SCB_ABORTED | SCB_PAGED_OUT))) { -#ifdef AIC7XXX_DEBUG_ABORT - printk ("aic7xxx: (abort_scb) scb %d is disconnected; " - "bus device reset message queued.\n", scb->position); +#if 0 + if (scb->control & TAG_ENB) + { + /* + * We could be starving this command; try sending and ordered tag + * command to the target we come from. + */ + scb->state = scb->state | SCB_ABORTED | SCB_SENTORDEREDTAG; + p->orderedtag = p->orderedtag | 0xFF; + result = SCSI_RESET_PENDING; + UNPAUSE_SEQUENCER(p); + printk(KERN_WARNING "aic7xxx: (abort_reset) Ordered tag queued.\n"); + } #endif - scb->state |= (SCB_DEVICE_RESET | SCB_ABORTED); - scb->SG_segment_count = 0; - memset(scb->SG_list_pointer, 0, sizeof(scb->SG_list_pointer)); - memset(scb->data_pointer, 0, sizeof(scb->data_pointer)); - scb->data_count = 0; - aic7xxx_putscb(p, scb); - aic7xxx_add_waiting_scb(base, scb); - aic7xxx_error(scb->cmd) = errcode; - scb_status = ABORT_RESET_PENDING; - outb(active_scb, SCBPTR + base); - UNPAUSE_SEQUENCER(p); - } - else - { + unsigned char active_scb, control; + struct aic7xxx_scb *active_scbp; + + /* + * Send a Bus Device Reset Message: + * The target we select to send the message to may be entirely + * different than the target pointed to by the scb that timed + * out. If the command is in the QINFIFO or the waiting for + * selection list, its not tying up the bus and isn't responsible + * for the delay so we pick off the active command which should + * be the SCB selected by SCBPTR. If its disconnected or active, + * we device reset the target scbp points to. Although it may + * be that this target is not responsible for the delay, it may + * may also be that we're timing out on a command that just takes + * too much time, so we try the bus device reset there first. + */ + active_scb = inb(SCBPTR + base); + active_scbp = &(p->scb_array[inb(SCB_TAG + base)]); + control = inb(SCB_CONTROL + base); + /* - * Is the active SCB really active? + * Test to see if scbp is disconnected */ - if ((active_scbp->state & SCB_ACTIVE) && bus_state) + outb(scb->position, SCBPTR + base); + if (inb(SCB_CONTROL + base) & DISCONNECTED) { - /* - * Load the message buffer and assert attention. - */ - active_scbp->state |= (SCB_DEVICE_RESET | SCB_ABORTED); - outb(1, MSG_LEN + base); - outb(MSG_BUS_DEVICE_RESET, MSG0 + base); - outb(bus_state | ATNO, SCSISIGO + base); #ifdef AIC7XXX_DEBUG_ABORT - printk ("aic7xxx: (abort_scb) asserted ATN - " - "bus device reset in message buffer.\n"); + printk("aic7xxx: (abort_scb) scb %d is disconnected; " + "bus device reset message queued.\n", scb->position); #endif - if (active_scbp != scb) + if (p->flags & PAGE_ENABLED) { - /* - * XXX - We would like to increment the timeout on scb, but - * access to that routine is denied because it is hidden - * in scsi.c. If we were able to do this, it would give - * scb a new lease on life. - */ - ; + /* Pull this SCB out of the disconnected list. */ + u_char prev = inb(SCB_PREV + base); + u_char next = inb(SCB_NEXT + base); + if (prev == SCB_LIST_NULL) + { + /* Head of list */ + outb(next, DISCONNECTED_SCBH + base); + } + else + { + outb(prev, SCBPTR + base); + outb(next, SCB_NEXT + base); + if (next != SCB_LIST_NULL) + { + outb(next, SCBPTR + base); + outb(prev, SCB_PREV + base); + } + outb(scb->position, SCBPTR + base); + } } - aic7xxx_error(scb->cmd) = errcode; - scb_status = ABORT_RESET_PENDING; - /* - * Restore the active SCB and unpause the sequencer. - */ - outb(active_scb, SCBPTR + base); - - UNPAUSE_SEQUENCER(p); + scb->state |= (SCB_DEVICE_RESET | SCB_ABORTED); + scb->control = scb->control & DISCENB; + scb->SCSI_cmd_length = 0; + scb->SG_segment_count = 0; + memset(scb->SG_list_pointer, 0, sizeof(scb->SG_list_pointer)); + memset(scb->data_pointer, 0, sizeof(scb->data_pointer)); + scb->data_count = 0; + aic7xxx_putscb(p, scb); + aic7xxx_add_waiting_scb(base, scb); + outb(active_scb, SCBPTR + base); + result = SCSI_RESET_PENDING; + UNPAUSE_SEQUENCER(p); } else { + /* + * Is the active SCB really active? + */ + if ((active_scbp->state & SCB_ACTIVE) && bus_state) + { + /* + * Load the message buffer and assert attention. + */ + active_scbp->state |= (SCB_DEVICE_RESET | SCB_ABORTED); + outb(1, MSG_LEN + base); + outb(MSG_BUS_DEVICE_RESET, MSG0 + base); + outb(bus_state | ATNO, SCSISIGO + base); #ifdef AIC7XXX_DEBUG_ABORT - printk ("aic7xxx: (abort_scb) no active command.\n"); + printk("aic7xxx: (abort_scb) asserted ATN - " + "bus device reset in message buffer.\n"); #endif - /* - * No active command to single out, so reset - * the bus for the timed out target. - */ - aic7xxx_reset_channel(p, channel, scb->position, TRUE); + if (active_scbp != scb) + { + /* + * XXX - We would like to increment the timeout on scb, but + * access to that routine is denied because it is hidden + * in scsi.c. If we were able to do this, it would give + * scb a new lease on life. + */ + ; + } + aic7xxx_error(scb->cmd) = DID_RESET; + /* + * Restore the active SCB and unpause the sequencer. + */ + outb(active_scb, SCBPTR + base); + if (active_scbp != scb) + { + /* + * The mid-level SCSI code requested us to reset a command + * different from the one that we actually reset. Return + * a "not running" indication and hope that the SCSI code + * will Do the Right Thing (tm). + */ + result = SCSI_RESET_NOT_RUNNING; + } + else + { + result = SCSI_RESET_PENDING; + } + UNPAUSE_SEQUENCER(p); + } } } } + restore_flags(flags); } - else - { - /* - * The scb is not active and must have completed after the timeout - * check in scsi.c and before we check the scb state above. For - * this case we return SCSI_ABORT_NOT_RUNNING (if abort was called) - * or SCSI_RESET_SUCCESS (if reset was called). - */ -#ifdef AIC7XXX_DEBUG_ABORT - printk ("aic7xxx: (abort_reset) called with no active scb, errcode 0x%x\n", - errcode); -#endif - scb_status = ABORT_RESET_INACTIVE; - /* - * According to the comments in scsi.h and Michael Neuffer, if we do not - * have an active command for abort or reset, we should not call the - * command done function. Unfortunately, this hangs the system for me - * unless we *do* call the done function. - * - * XXX - Revisit this sometime! - */ - cmd->result = errcode << 16; - cmd->scsi_done(cmd); - } - - restore_flags(flags); - return (scb_status); + return (result); } @@ -4608,25 +5319,39 @@ int aic7xxx_abort(Scsi_Cmnd *cmd) { + struct aic7xxx_scb *scb = NULL; + struct aic7xxx_host *p; + int base, result; + + p = (struct aic7xxx_host *) cmd->host->hostdata; + scb = &(p->scb_array[aic7xxx_position(cmd)]); + base = p->base; + #ifdef AIC7XXX_DEBUG_ABORT - printk ("aic7xxx: (abort) target/channel %d/%d\n", cmd->target, cmd->channel); + printk("aic7xxx: (abort) Aborting scb %d, TCL %d/%d/%d\n", + scb->position, TCL_OF_SCB(scb)); #endif - switch (aic7xxx_abort_reset(cmd, DID_ABORT)) + if (cmd->serial_number != cmd->serial_number_at_timeout) { - case ABORT_RESET_INACTIVE: - return (SCSI_ABORT_NOT_RUNNING); - break; - case ABORT_RESET_PENDING: - return (SCSI_ABORT_PENDING); - break; - case ABORT_RESET_SUCCESS: - default: - return (SCSI_ABORT_SUCCESS); - break; + result = SCSI_ABORT_NOT_RUNNING; } + else if (scb == NULL) + { + result = SCSI_ABORT_NOT_RUNNING; + } + else if ((scb->cmd != cmd) || (!(scb->state & SCB_IN_PROGRESS))) + { + result = SCSI_ABORT_NOT_RUNNING; + } + else + { + result = SCSI_ABORT_SNOOZE; + } + return (result); } + /*+F************************************************************************* * Function: * aic7xxx_reset @@ -4638,25 +5363,150 @@ * the SCSI bus reset line. *-F*************************************************************************/ int -aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int resetFlags) +aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags) { + struct aic7xxx_scb *scb = NULL; + struct aic7xxx_host *p; + int base, found, tindex, min_target, max_target, result = -1; + char channel = 'A'; + + p = (struct aic7xxx_host *) cmd->host->hostdata; + scb = &(p->scb_array[aic7xxx_position(cmd)]); + base = p->base; + channel = cmd->channel ? 'B': 'A'; + tindex = (cmd->channel << 4) | cmd->target; + #ifdef AIC7XXX_DEBUG_ABORT - printk ("aic7xxx: (reset) target/channel %d/%d\n", cmd->target, cmd->channel); + printk("aic7xxx: (reset) target/channel %d/%d\n", cmd->target, cmd->channel); #endif - switch (aic7xxx_abort_reset(cmd, DID_RESET)) + if (scb->cmd != cmd) + scb = NULL; + + if (!(flags & SCSI_RESET_SUGGEST_HOST_RESET) && (scb != NULL)) { - case ABORT_RESET_PENDING: - return (SCSI_RESET_PENDING); - break; - case ABORT_RESET_SUCCESS: - return (SCSI_RESET_BUS_RESET | SCSI_RESET_SUCCESS); - break; - case ABORT_RESET_INACTIVE: - default: - return (SCSI_RESET_SUCCESS); - break; + /* + * Attempt a bus device reset if commands have completed successfully + * since the last bus device reset, or it has been less than 100ms + * since the last reset. + */ + if ((p->flags & DEVICE_SUCCESS) || + ((jiffies - p->device_status[tindex].last_reset) < HZ/10)) + { + if (cmd->serial_number != cmd->serial_number_at_timeout) + { + result = SCSI_RESET_NOT_RUNNING; + } + else + { + if (scb == NULL) + { + result = SCSI_RESET_NOT_RUNNING; + } + else if (flags & SCSI_RESET_ASYNCHRONOUS) + { + if (scb->state & SCB_ABORTED) + { + result = SCSI_RESET_PENDING; + } + else if (!(scb->state & SCB_IN_PROGRESS)) + { + result = SCSI_RESET_NOT_RUNNING; + } + } + + if (result == -1) + { + if ((flags & SCSI_RESET_SYNCHRONOUS) && + (p->device_status[tindex].flags & BUS_DEVICE_RESET_PENDING)) + { + scb->state |= SCB_ABORTED; + result = SCSI_RESET_PENDING; + } + else + { + result = aic7xxx_bus_device_reset(p, cmd); + if (result == 0) + result = SCSI_RESET_PENDING; + } + } + } + } + } + + if (result == -1) + { + /* + * The bus device reset failed; try resetting the channel. + */ + if (flags & SCSI_RESET_ASYNCHRONOUS) + { + if (scb == NULL) + { + result = SCSI_RESET_NOT_RUNNING; + } + else if (!(scb->state & SCB_IN_PROGRESS)) + { + result = SCSI_RESET_NOT_RUNNING; + } + else if ((scb->state & SCB_ABORTED) && + (!(p->device_status[tindex].flags & BUS_DEVICE_RESET_PENDING))) + { + result = SCSI_RESET_PENDING; + } + } + + if (result == -1) + { + found = aic7xxx_reset_channel(p, channel, TRUE); + + /* + * If this is a synchronous reset and there is no SCB for this + * command, perform completion processing. + * + */ + if ((flags & SCSI_RESET_SYNCHRONOUS) && (scb == NULL)) + { + cmd->result = DID_RESET << 16; + cmd->scsi_done(cmd); + } + + switch (p->bus_type) + { + case AIC_TWIN: + if (channel == 'B') + { + min_target = 8; + max_target = 15; + } + else + { + min_target = 0; + max_target = 7; + } + break; + + case AIC_WIDE: + min_target = 0; + max_target = 15; + break; + + case AIC_SINGLE: + default: + min_target = 0; + max_target = 7; + break; + } + + for (tindex = min_target; tindex <= max_target; tindex++) + { + p->device_status[tindex].last_reset = jiffies; + } + + result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET; + } } + return (result); } /*+F************************************************************************* @@ -4683,7 +5533,7 @@ sectors = 32; cylinders = disk->capacity / (heads * sectors); - if (p->extended && (cylinders > 1024)) + if ((p->flags & EXTENDED_TRANSLATION) && (cylinders > 1024)) { heads = 255; sectors = 63; diff -ur --new-file old/linux/drivers/scsi/aic7xxx.h new/linux/drivers/scsi/aic7xxx.h --- old/linux/drivers/scsi/aic7xxx.h Sun May 12 20:52:55 1996 +++ new/linux/drivers/scsi/aic7xxx.h Sat Aug 10 09:44:18 1996 @@ -18,12 +18,12 @@ * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: aic7xxx.h,v 3.1 1996/05/12 17:25:20 deang Exp $ + * $Id: aic7xxx.h,v 3.2 1996/07/23 03:37:26 deang Exp $ *-M*************************************************************************/ #ifndef _aic7xxx_h #define _aic7xxx_h -#define AIC7XXX_H_VERSION "$Revision: 3.1 $" +#define AIC7XXX_H_VERSION "$Revision: 3.2 $" /* * Scsi_Host_Template (see hosts.h) for AIC-7xxx - some fields @@ -58,7 +58,7 @@ extern int aic7xxx_detect(Scsi_Host_Template *); extern int aic7xxx_command(Scsi_Cmnd *); extern int aic7xxx_abort(Scsi_Cmnd *); -extern int aic7xxx_reset(Scsi_Cmnd *, unsigned int resetFlags); +extern int aic7xxx_reset(Scsi_Cmnd *, unsigned int); extern const char *aic7xxx_info(struct Scsi_Host *); diff -ur --new-file old/linux/drivers/scsi/aic7xxx.seq new/linux/drivers/scsi/aic7xxx.seq --- old/linux/drivers/scsi/aic7xxx.seq Sat Apr 20 19:59:10 1996 +++ new/linux/drivers/scsi/aic7xxx.seq Sat Aug 10 09:44:18 1996 @@ -23,15 +23,22 @@ * * FreeBSD, Twin, Wide, 2 command per target support, tagged queuing and other * optimizations provided by Justin T. Gibbs (gibbs@FreeBSD.org) + * + * This version corresponds to version 1.42 of FreeBSDs aic7xxx.seq. + * *-M*************************************************************************/ -VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 3.0 1996/04/16 08:52:23 deang Exp $" +VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 3.1 1996/07/23 03:37:26 deang Exp $" #ifdef linux #include "aic7xxx_reg.h" #else +#if defined(__NetBSD__) +#include "../../../../dev/ic/aic7xxxreg.h" +#elif defined(__FreeBSD__) #include "../../dev/aic7xxx/aic7xxx_reg.h" #endif +#endif /* * We can't just use ACCUM in the sequencer code because it @@ -67,7 +74,13 @@ * We jump to start after every bus free. */ start: + and FLAGS,0x0f /* clear target specific flags */ mvi SCSISEQ,ENRSELI /* Always allow reselection */ + clr SCSIRATE /* + * We don't know the target we will + * connect to, so default to narrow + * transfers to avoid parity problems. + */ poll_for_work: /* * Are we a twin channel device? @@ -140,7 +153,7 @@ or ACTIVE_A,A start_scb: - mov SCB_NEXT_WAITING,WAITING_SCBH + mov SCB_NEXT,WAITING_SCBH mov WAITING_SCBH, SCBPTR start_scb2: and SINDEX,0xf7,SBLKCTL /* Clear the channel select bit */ @@ -178,25 +191,24 @@ jmp wait_for_selection mk_identify: - and A,DISCENB,SCB_CONTROL /* mask off disconnect privilege */ + and A,DISCENB,SCB_CONTROL /* mask off disconnect privledge */ and MSG0,0x7,SCB_TCL /* lun */ - or MSG0,A /* or in disconnect privilege */ + or MSG0,A /* or in disconnect privledge */ or MSG0,MSG_IDENTIFY mvi MSG_LEN, 1 test SCB_CONTROL,0xb0 jz !message /* WDTR, SDTR or TAG?? */ /* - * Tag Message if Tag enabled in SCB control block. Use SCBPTR as the tag - * value + * Send a tag message if TAG_ENB is set in the SCB control block. + * Use SCB_TAG (the position in the kernel's SCB array) as the tag value. */ mk_tag: mvi DINDEX, MSG1 test SCB_CONTROL,TAG_ENB jz mk_tag_done - and A,0x23,SCB_CONTROL - mov DINDIR,A - mov DINDIR,SCBPTR + and DINDIR,0x23,SCB_CONTROL + mov DINDIR,SCB_TAG add MSG_LEN,COMP_MSG0,DINDEX /* update message length */ @@ -218,7 +230,6 @@ reselect: clr MSG_LEN /* Don't have anything in the mesg buffer */ mov SELID call initialize_scsiid - and FLAGS,0x03 /* clear target specific flags */ or FLAGS,RESELECTED jmp select2 @@ -229,8 +240,8 @@ * SCB is used, so don't bother with it now. */ select: - and FLAGS,0x03 /* Clear target flags */ - mov WAITING_SCBH,SCB_NEXT_WAITING + mov WAITING_SCBH,SCB_NEXT + or FLAGS,SELECTED select2: /* * Set CLRCHN here before the target has entered a data transfer mode - @@ -244,13 +255,29 @@ call ndx_dtr mov SCSIRATE,SINDIR +/* + * Initialize Ultra mode setting. + */ + mov FUNCTION1,SCSIID + mov A,FUNCTION1 + and SINDEX,0xdf,SXFRCTL0 /* default to Ultra disabled */ + test SCSIID, 0x80 jnz ultra_b /* Target ID > 7 */ + test SBLKCTL, SELBUSB jnz ultra_b /* Second channel device */ + test ULTRA_ENB,A jz set_sxfrctl0 + or SINDEX, ULTRAEN jmp set_sxfrctl0 +ultra_b: + test ULTRA_ENB_B,A jz set_sxfrctl0 + or SINDEX, ULTRAEN + +set_sxfrctl0: + mov SXFRCTL0,SINDEX + mvi SCSISEQ,ENAUTOATNP /* * ATN on parity errors * for "in" phases */ mvi CLRSINT1,CLRBUSFREE mvi CLRSINT0,0x60 /* CLRSELDI|CLRSELDO */ - /* * Main loop for information transfer phases. If BSY is false, then * we have a bus free condition, expected or not. Otherwise, wait @@ -274,6 +301,7 @@ cmp A,P_MESGIN je p_mesgin mvi INTSTAT,BAD_PHASE /* unknown phase - signal driver */ + jmp ITloop /* Try reading the bus again. */ p_dataout: mvi DMAPARAMS,0x7d /* @@ -305,12 +333,29 @@ or FLAGS, DPHASE /* We have seen a data phase */ data_phase_loop: +/* Guard against overruns */ + test SG_COUNT, 0xff jnz data_phase_inbounds +/* + * Turn on 'Bit Bucket' mode, set the transfer count to + * 16meg and let the target run until it changes phase. + * When the transfer completes, notify the host that we + * had an overrun. + */ + or SXFRCTL1,BITBUCKET + mvi STCNT0,0xff + mvi STCNT1,0xff + mvi STCNT2,0xff + +data_phase_inbounds: /* If we are the last SG block, don't set wideodd. */ cmp SG_COUNT,0x01 jne data_phase_wideodd and DMAPARAMS, 0xbf /* Turn off WIDEODD */ data_phase_wideodd: mov DMAPARAMS call dma +/* Go tell the host about any overruns */ + test SXFRCTL1,BITBUCKET jnz data_phase_overrun + /* Exit if we had an underrun */ test SSTAT0,SDONE jz data_phase_finish /* underrun STCNT != 0 */ @@ -412,16 +457,22 @@ mov SCB_RESID_SGCNT, SG_COUNT jmp ITloop +data_phase_overrun: +/* + * Turn off BITBUCKET mode and notify the host + */ + and SXFRCTL1,0x7f /* ~BITBUCKET */ + mvi INTSTAT,DATA_OVERRUN + jmp ITloop + /* - * Command phase. Set up the DMA registers and let 'er rip - the - * two bytes after the SCB SCSI_cmd_length are zeroed by the driver, - * so we can copy those three bytes directly into HCNT. + * Command phase. Set up the DMA registers and let 'er rip. */ p_command: call assert /* - * Load HADDR and HCNT. We can do this in one bcopy since they are neighbors + * Load HADDR and HCNT. */ mov HADDR0, SCB_CMDPTR0 mov HADDR1, SCB_CMDPTR1 @@ -448,7 +499,7 @@ jmp mesgin_done /* - * Message out phase. If there is no active message, but the target + * Message out phase. If there is not an active message, but the target * took us into this phase anyway, build a no-op message and send it. */ p_mesgout: @@ -473,6 +524,7 @@ p_mesgout_loop: test SSTAT1,PHASEMIS jnz p_mesgout_phasemis test SSTAT0,SPIORDY jz p_mesgout_loop + test SSTAT1,PHASEMIS jnz p_mesgout_phasemis cmp DINDEX,1 jne p_mesgout_outb /* last byte? */ mvi CLRSINT1,CLRATNO /* drop ATN */ p_mesgout_outb: @@ -498,7 +550,7 @@ jmp ITloop p_mesgout_phasemis: - mvi CLRSINT1,CLRATNO /* Be sure turn ATNO off */ + mvi CLRSINT1,CLRATNO /* Be sure to turn ATNO off */ p_mesgout_done: clr MSG_LEN /* no active msg */ jmp ITloop @@ -539,20 +591,20 @@ mesgin_complete: /* - * We got a "command complete" message, so put the SCB pointer - * into QUEUEOUT, and trigger a completion interrupt. - * Check status for non zero return and interrupt driver if needed - * This allows the driver to interpret errors only when they occur - * instead of always uploading the scb. If the status is SCSI_CHECK, - * the driver will download a new scb requesting sense to replace - * the old one, modify the "waiting for selection" SCB list and set - * RETURN_1 to 0x80. If RETURN_1 is set to 0x80 the sequencer immediately - * jumps to main loop where it will run down the waiting SCB list. - * If the kernel driver does not wish to request sense, it need - * only clear RETURN_1, and the command is allowed to complete. We don't - * bother to post to the QOUTFIFO in the error case since it would require - * extra work in the kernel driver to ensure that the entry was removed - * before the command complete code tried processing it. + * We got a "command complete" message, so put the SCB_TAG into QUEUEOUT, + * and trigger a completion interrupt. Check status for non zero return + * and interrupt driver if needed. This allows the driver to interpret + * errors only when they occur instead of always uploading the scb. If + * the status is SCSI_CHECK, the driver will download a new scb requesting + * sense to replace the old one, modify the "waiting for selection" SCB list + * and set RETURN_1 to SEND_SENSE. If RETURN_1 is set to SEND_SENSE the + * sequencer imediately jumps to main loop where it will run down the waiting + * SCB list and process the sense request. If the kernel driver does not + * wish to request sense, it need only clear RETURN_1, and the command is + * allowed to complete. We don't bother to post to the QOUTFIFO in the + * error case since it would require extra work in the kernel driver to + * ensure that the entry was removed before the command complete code tried + * processing it. * * First check for residuals */ @@ -600,7 +652,7 @@ mvi INTSTAT,IMMEDDONE jmp start complete: - mov QOUTFIFO,SCBPTR + mov QOUTFIFO,SCB_TAG mvi INTSTAT,CMDCMPLT jmp mesgin_done @@ -614,10 +666,10 @@ */ mesgin_extended: mvi ARG_1 call inb_next /* extended message length */ - mvi A call inb_next /* extended message code */ + mvi REJBYTE_EXT call inb_next /* extended message code */ - cmp A,MSG_SDTR je p_mesginSDTR - cmp A,MSG_WDTR je p_mesginWDTR + cmp REJBYTE_EXT,MSG_SDTR je p_mesginSDTR + cmp REJBYTE_EXT,MSG_WDTR je p_mesginWDTR jmp rej_mesgin p_mesginWDTR: @@ -648,6 +700,7 @@ * Requested SDTR too small * Reject it. */ + clr ARG_1 /* Use the scratch ram rate */ mvi DINDEX, MSG0 mvi MSG0 call mk_sdtr or SCSISIGO,ATNO /* turn on ATNO */ @@ -659,6 +712,22 @@ */ mesgin_disconnect: or SCB_CONTROL,DISCONNECTED + test FLAGS, PAGESCBS jz mesgin_done +/* + * Link this SCB into the DISCONNECTED list. This list holds the + * candidates for paging out an SCB if one is needed for a new command. + * Modifying the disconnected list is a critical(pause dissabled) section. + */ + mvi SCB_PREV, SCB_LIST_NULL + mvi SEQCTL,0x50 /* PAUSEDIS|FASTMODE */ + mov SCB_NEXT, DISCONNECTED_SCBH + mov DISCONNECTED_SCBH, SCBPTR + cmp SCB_NEXT,SCB_LIST_NULL je linkdone + mov SCBPTR,SCB_NEXT + mov SCB_PREV,DISCONNECTED_SCBH + mov SCBPTR,DISCONNECTED_SCBH +linkdone: + mvi SEQCTL,0x10 /* !PAUSEDIS|FASTMODE */ jmp mesgin_done /* @@ -676,7 +745,7 @@ * code do the rest. */ mesgin_rdptrs: - and FLAGS,0xfb /* + and FLAGS,0xef /* * !DPHASE we'll reload them * the next time through */ @@ -699,21 +768,19 @@ /* * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message. - * If we get one, we use the tag returned to switch to the proper - * SCB. Otherwise, we just use the findSCB method. + * If we get one, we use the tag returned to switch to find the proper + * SCB. With SCB paging, this requires using findSCB for both tagged + * and non-tagged transactions since the SCB may exist in any slot. + * If we're not using SCB paging, we can use the tag as the direct + * index to the SCB. */ + mvi ARG_1,SCB_LIST_NULL /* Default to no-tag */ snoop_tag_loop: test SSTAT1,BUSFREE jnz use_findSCB test SSTAT1,REQINIT jz snoop_tag_loop test SSTAT1,PHASEMIS jnz use_findSCB mvi A call inb_first - cmp A,MSG_SIMPLE_TAG je get_tag -use_findSCB: - mov ALLZEROS call findSCB /* Have to search */ -setup_SCB: - and SCB_CONTROL,0xfb /* clear disconnect bit in SCB */ - or FLAGS,IDENTIFY_SEEN /* make note of IDENTIFY */ - jmp ITloop + cmp A,MSG_SIMPLE_TAG jne use_findSCB get_tag: mvi ARG_1 call inb_next /* tag value */ /* @@ -729,16 +796,26 @@ * Ensure that the SCB the tag points to is for a SCB transaction * to the reconnecting target. */ + test FLAGS, PAGESCBS jz index_by_tag + call inb_last /* Ack Tag */ +use_findSCB: + mov ALLZEROS call findSCB /* Have to search */ +setup_SCB: + and SCB_CONTROL,0xfb /* clear disconnect bit in SCB */ + or FLAGS,IDENTIFY_SEEN /* make note of IDENTIFY */ + jmp ITloop +index_by_tag: mov SCBPTR,ARG_1 mov A,SAVED_TCL cmp SCB_TCL,A jne abort_tag test SCB_CONTROL,TAG_ENB jz abort_tag call inb_last /* Ack Successful tag */ jmp setup_SCB + abort_tag: or SCSISIGO,ATNO /* turn on ATNO */ mvi INTSTAT,ABORT_TAG /* let driver know */ - mvi 0xd call mk_mesg /* ABORT TAG message */ + mvi MSG_ABORT_TAG call mk_mesg /* ABORT TAG message */ jmp mesgin_done /* @@ -778,7 +855,7 @@ mk_mesg: mvi SEQCTL,0x50 /* PAUSEDIS|FASTMODE */ test MSG_LEN,0xff jz mk_mesg1 /* Should always succeed */ - + /* * Hmmm. For some reason the mesg buffer is in use. * Tell the driver. It should look at SINDEX to find @@ -817,6 +894,7 @@ test SSTAT0,SPIORDY jz inb_next_wait /* wait for next byte */ inb_first: mov DINDEX,SINDEX + test SSTAT1,PHASEMIS jnz mesgin_phasemis mov DINDIR,SCSIBUSL ret /*read byte directly from bus*/ inb_last: mov NONE,SCSIDATL ret /*dummy read from latch to ACK*/ @@ -887,27 +965,59 @@ mvi INTSTAT,NO_IDENT ret /* no - cause a kernel panic */ /* - * Locate the SCB matching the target ID/channel/lun in SAVED_TCL and switch - * the SCB to it. Have the kernel print a warning message if it can't be - * found, and generate an ABORT message to the target. SINDEX should be + * Locate the SCB matching the target ID/channel/lun in SAVED_TCL, and the tag + * value in ARG_1. If ARG_1 == SCB_LIST_NULL, we're looking for a non-tagged + * SCB. Have the kernel print a warning message if it can't be found, and + * generate an ABORT/ABORT_TAG message to the target. SINDEX should be * cleared on call. */ findSCB: mov A,SAVED_TCL - mov SCBPTR,SINDEX /* switch to new SCB */ + mov SCBPTR,SINDEX /* switch to next SCB */ + mvi SEQCTL,0x50 /* PAUSEDIS|FASTMODE */ cmp SCB_TCL,A jne findSCB1 /* target ID/channel/lun match? */ test SCB_CONTROL,DISCONNECTED jz findSCB1 /*should be disconnected*/ - ret + test SCB_CONTROL,TAG_ENB jnz findTaggedSCB + cmp ARG_1,SCB_LIST_NULL je foundSCB + jmp findSCB1 +findTaggedSCB: + mov A, ARG_1 /* Tag passed in ARG_1 */ + cmp SCB_TAG,A jne findSCB1 /* Found it? */ +foundSCB: + test FLAGS,PAGESCBS jz foundSCB_ret +/* Remove this SCB from the disconnection list */ + cmp SCB_NEXT,SCB_LIST_NULL je unlink_prev + mov SAVED_LINKPTR, SCB_PREV + mov SCBPTR, SCB_NEXT + mov SCB_PREV, SAVED_LINKPTR + mov SCBPTR, SINDEX +unlink_prev: + cmp SCB_PREV,SCB_LIST_NULL je rHead/* At the head of the list */ + mov SAVED_LINKPTR, SCB_NEXT + mov SCBPTR, SCB_PREV + mov SCB_NEXT, SAVED_LINKPTR + mov SCBPTR, SINDEX + mvi SEQCTL,0x10 ret /* !PAUSEDIS|FASTMODE */ +rHead: + mov DISCONNECTED_SCBH,SCB_NEXT +foundSCB_ret: + mvi SEQCTL,0x10 ret /* !PAUSEDIS|FASTMODE */ findSCB1: + mvi SEQCTL,0x10 /* !PAUSEDIS|FASTMODE */ inc SINDEX mov A,SCBCOUNT cmp SINDEX,A jne findSCB mvi INTSTAT,NO_MATCH /* not found - signal kernel */ - mvi MSG_ABORT call mk_mesg /* ABORT message */ - - or SCSISIGO,ATNO ret /* assert ATNO */ + cmp RETURN_1,SCB_PAGEDIN je return + or SCSISIGO,ATNO /* assert ATNO */ + cmp ARG_1,SCB_LIST_NULL jne find_abort_tag + mvi MSG_ABORT call mk_mesg + jmp ITloop +find_abort_tag: + mvi MSG_ABORT_TAG call mk_mesg + jmp ITloop /* * Make a working copy of the scatter-gather parameters from the SCB. @@ -980,7 +1090,7 @@ */ mk_dtr: test SCB_CONTROL,NEEDWDTR jnz mk_wdtr_16bit - or FLAGS, MAXOFFSET /* Force an offset of 15 or 8 if WIDE */ + mvi ARG_1, MAXOFFSET /* Force an offset of 15 or 8 if WIDE */ mk_sdtr: mvi DINDIR,1 /* extended message */ @@ -988,7 +1098,7 @@ mvi DINDIR,1 /* SDTR code */ call sdtr_to_rate mov DINDIR,RETURN_1 /* REQ/ACK transfer period */ - test FLAGS, MAXOFFSET jnz mk_sdtr_max_offset + cmp ARG_1, MAXOFFSET je mk_sdtr_max_offset and DINDIR,0x0f,SINDIR /* Sync Offset */ mk_sdtr_done: @@ -998,8 +1108,6 @@ /* * We're initiating sync negotiation, so request the max offset we can (15 or 8) */ - xor FLAGS, MAXOFFSET - /* Talking to a WIDE device? */ test SCSIRATE, WIDEXFER jnz wmax_offset mvi DINDIR, MAX_OFFSET_8BIT diff -ur --new-file old/linux/drivers/scsi/aic7xxx_proc.c new/linux/drivers/scsi/aic7xxx_proc.c --- old/linux/drivers/scsi/aic7xxx_proc.c Sun May 12 20:52:55 1996 +++ new/linux/drivers/scsi/aic7xxx_proc.c Sat Aug 10 09:44:18 1996 @@ -24,7 +24,7 @@ * * Dean W. Gehnert, deang@teleport.com, 05/01/96 * - * $Id: aic7xxx_proc.c,v 3.1 1996/05/12 17:25:56 deang Exp $ + * $Id: aic7xxx_proc.c,v 3.2 1996/07/23 03:37:26 deang Exp $ *-M*************************************************************************/ #define BLS buffer + len + size @@ -151,10 +151,10 @@ #else size += sprintf(BLS, " AIC7XXX_TAGGED_QUEUEING: Disabled\n"); #endif -#ifdef AIC7XXX_SHARE_IRQS - size += sprintf(BLS, " AIC7XXX_SHARE_IRQS : Enabled\n"); +#ifdef AIC7XXX_PAGE_ENABLE + size += sprintf(BLS, " AIC7XXX_PAGE_ENABLE : Enabled\n"); #else - size += sprintf(BLS, " AIC7XXX_SHARE_IRQS : Disabled\n"); + size += sprintf(BLS, " AIC7XXX_PAGE_ENABLE : Disabled\n"); #endif #ifdef AIC7XXX_PROC_STATS size += sprintf(BLS, " AIC7XXX_PROC_STATS : Enabled\n"); @@ -171,7 +171,8 @@ size += sprintf(BLS, " Host Bus: %s\n", bus_names[p->bus_type]); size += sprintf(BLS, " Base IO: %#.4x\n", p->base); size += sprintf(BLS, " IRQ: %d\n", HBAptr->irq); - size += sprintf(BLS, " SCB: %d (%d)\n", p->numscb, p->maxscb); + size += sprintf(BLS, " SCBs: Used %d, HW %d, Page %d\n", + p->numscbs, p->maxhscbs, p->maxscbs); size += sprintf(BLS, " Interrupts: %d", p->isr_count); if (p->chip_type == AIC_777x) { @@ -183,13 +184,13 @@ size += sprintf(BLS, "\n"); } size += sprintf(BLS, " Serial EEPROM: %s\n", - p->have_seeprom ? "True" : "False"); + (p->flags & HAVE_SEEPROM) ? "True" : "False"); size += sprintf(BLS, " Extended Translation: %sabled\n", - p->extended ? "En" : "Dis"); + (p->flags & EXTENDED_TRANSLATION) ? "En" : "Dis"); size += sprintf(BLS, " SCSI Bus Reset: %sabled\n", aic7xxx_no_reset ? "Dis" : "En"); size += sprintf(BLS, " Ultra SCSI: %sabled\n", - p->ultra_enabled ? "En" : "Dis"); + (p->flags & ULTRA_ENABLED) ? "En" : "Dis"); size += sprintf(BLS, " Target Disconnect: %sabled\n", p->discenable ? "En" : "Dis"); len += size; pos = begin + len; size = 0; diff -ur --new-file old/linux/drivers/scsi/aic7xxx_reg.h new/linux/drivers/scsi/aic7xxx_reg.h --- old/linux/drivers/scsi/aic7xxx_reg.h Sat Apr 20 19:59:10 1996 +++ new/linux/drivers/scsi/aic7xxx_reg.h Sat Aug 10 09:44:18 1996 @@ -18,7 +18,9 @@ * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * - * $Id: aic7xxx_reg.h,v 3.0 1996/04/16 08:52:23 deang Exp $ + * This version corresponds to version 1.12 of FreeBSDs aic7xxx_reg.h + * + * $Id: aic7xxx_reg.h,v 3.1 1996/07/23 03:37:26 deang Exp $ *-M*************************************************************************/ /* @@ -331,7 +333,6 @@ #define HCNT0 0x08c #define HCNT1 0x08d #define HCNT2 0x08e - /* * SCB Pointer (p. 3-49) * Gate one of the four SCBs into the SCBARRAY window. @@ -363,7 +364,6 @@ #define BUSTIME 0x085 #define BOFF 0xf0 #define BON 0x0f -#define BOFF_60BCLKS 0xf0 /* * Bus Speed (p. 3-45) @@ -387,6 +387,7 @@ #define PAUSE 0x04 #define INTEN 0x02 #define CHIPRST 0x01 +#define CHIPRSTACK 0x01 /* * Interrupt Status (p. 3-50) @@ -425,6 +426,11 @@ * when we were expecting * another msgin byte. */ +#define DATA_OVERRUN 0xe1 /* + * Target attempted to write + * beyond the bounds of its + * command. + */ #define BRKADRINT 0x08 #define SCSIINT 0x04 #define CMDCMPLT 0x02 @@ -548,7 +554,9 @@ #define SCB_CMDPTR2 0x0b6 #define SCB_CMDPTR3 0x0b7 #define SCB_CMDLEN 0x0b8 -#define SCB_NEXT_WAITING 0x0b9 +#define SCB_TAG 0x0b9 +#define SCB_NEXT 0x0ba +#define SCB_PREV 0x0bb #ifdef linux #define SG_SIZEOF 0x0c /* sizeof(struct scatterlist) */ @@ -629,10 +637,12 @@ #define TARG_SCRATCH 0x020 /* - * The sequencer will stick the first byte of any rejected message here so - * we can see what is getting thrown away. + * The sequencer will stick the frist byte of any rejected message here so + * we can see what is getting thrown away. Extended messages put the + * extended message type in REJBYTE_EXT. */ -#define REJBYTE 0x031 +#define REJBYTE 0x030 +#define REJBYTE_EXT 0x031 /* * Bit vector of targets that have disconnection disabled. @@ -646,6 +656,7 @@ */ #define MSG_LEN 0x034 +/* We reserve 8bytes to store outgoing messages */ #define MSG0 0x035 #define COMP_MSG0 0xcb /* 2's complement of MSG0 */ #define MSG1 0x036 @@ -653,70 +664,90 @@ #define MSG3 0x038 #define MSG4 0x039 #define MSG5 0x03a +#define MSG6 0x03b +#define MSG7 0x03c /* * These are offsets into the card's scratch ram. Some of the values are * specified in the AHA2742 technical reference manual and are initialized * by the BIOS at boot time. */ -#define LASTPHASE 0x049 -#define ARG_1 0x04a -#define RETURN_1 0x04a -#define SEND_SENSE 0x80 +#define LASTPHASE 0x03d +#define ARG_1 0x03e +#define MAXOFFSET 0x01 +#define RETURN_1 0x03f #define SEND_WDTR 0x80 -#define SEND_SDTR 0x80 -#define SEND_REJ 0x40 - -#define SIGSTATE 0x04b - -#define DMAPARAMS 0x04c /* Parameters for DMA Logic */ +#define SEND_SDTR 0x60 +#define SEND_SENSE 0x40 +#define SEND_REJ 0x20 +#define SCB_PAGEDIN 0x10 + +#define SIGSTATE 0x040 + +#define DMAPARAMS 0x041 /* Parameters for DMA Logic */ + +#define SG_COUNT 0x042 +#define SG_NEXT 0x043 /* working value of SG pointer */ +#define SG_NEXT0 0x043 +#define SG_NEXT1 0x044 +#define SG_NEXT2 0x045 +#define SG_NEXT3 0x046 -#define SG_COUNT 0x04d -#define SG_NEXT 0x04e /* working value of SG pointer */ -#define SG_NEXT0 0x04e -#define SG_NEXT1 0x04f -#define SG_NEXT2 0x050 -#define SG_NEXT3 0x051 - -#define SCBCOUNT 0x052 /* +#define SCBCOUNT 0x047 /* * Number of SCBs supported by * this card. */ -#define FLAGS 0x053 +#define COMP_SCBCOUNT 0x048 /* + * Two's compliment of SCBCOUNT + */ +#define QCNTMASK 0x049 /* + * Mask of bits to test against + * when looking at the Queue Count + * registers. Works around a bug + * on aic7850 chips. + */ +#define FLAGS 0x04a #define SINGLE_BUS 0x00 #define TWIN_BUS 0x01 #define WIDE_BUS 0x02 -#define DPHASE 0x04 -#define MAXOFFSET 0x08 +#define PAGESCBS 0x04 +#define DPHASE 0x10 +#define SELECTED 0x20 #define IDENTIFY_SEEN 0x40 #define RESELECTED 0x80 -#define ACTIVE_A 0x054 -#define ACTIVE_B 0x055 -#define SAVED_TCL 0x056 /* +#define SAVED_TCL 0x04b /* * Temporary storage for the * target/channel/lun of a * reconnecting target */ -#define WAITING_SCBH 0x057 /* +#define ACTIVE_A 0x04c +#define ACTIVE_B 0x04d +#define WAITING_SCBH 0x04e /* * head of list of SCBs awaiting * selection */ -#define QCNTMASK 0x058 /* - * Mask of bits to test against - * when looking at the Queue Count - * registers. Works around a bug - * on aic7850 chips. +#define DISCONNECTED_SCBH 0x04f /* + * head of list of SCBs that are + * disconnected. Used for SCB + * paging. */ -#define COMP_SCBCOUNT 0x059 #define SCB_LIST_NULL 0xff +#define SAVED_LINKPTR 0x050 +#define SAVED_SCBPTR 0x051 +#define ULTRA_ENB 0x052 +#define ULTRA_ENB_B 0x053 + #define SCSICONF 0x05a +#define RESET_SCSI 0x40 + #define HOSTCONF 0x05d #define HA_274_BIOSCTRL 0x05f #define BIOSMODE 0x30 #define BIOSDISABLED 0x30 +#define CHANNEL_B_PRIMARY 0x08 /* Message codes */ #define MSG_EXTENDED 0x01 @@ -731,6 +762,7 @@ #define MSG_NOP 0x08 #define MSG_MSG_PARITY_ERROR 0x09 #define MSG_BUS_DEVICE_RESET 0x0c +#define MSG_ABORT_TAG 0x0d #define MSG_SIMPLE_TAG 0x20 #define MSG_IDENTIFY 0x80 @@ -741,4 +773,3 @@ #define MAX_OFFSET_8BIT 0x0f #define MAX_OFFSET_16BIT 0x08 - diff -ur --new-file old/linux/drivers/scsi/eata.c new/linux/drivers/scsi/eata.c --- old/linux/drivers/scsi/eata.c Thu Apr 18 13:56:45 1996 +++ new/linux/drivers/scsi/eata.c Wed Jul 10 07:05:27 1996 @@ -1,6 +1,9 @@ /* * eata.c - Low-level driver for EATA/DMA SCSI host adapters. * + * 09 Jul 1996 rev. 2.11 for linux 2.0.4 + * Number of internal retries is now limited. + * * 16 Apr 1996 rev. 2.10 for linux 1.3.90 * New argument "reset_flags" to the reset routine. * @@ -156,6 +159,7 @@ #define MAX_BOARDS 18 #define MAX_MAILBOXES 64 #define MAX_SGLIST 64 +#define MAX_INTERNAL_RETRIES 64 #define MAX_CMD_PER_LUN 2 #define FALSE 0 @@ -313,6 +317,8 @@ int in_reset; /* True if board is doing a reset */ int target_time_out[MAX_TARGET]; /* N. of timeout errors on target */ int target_reset[MAX_TARGET]; /* If TRUE redo operation on target */ + unsigned int retries; /* Number of internal retries */ + unsigned long last_retried_pid; /* Pid of last retried command */ unsigned char subversion; /* Bus type, either ISA or ESA */ unsigned char protocol_rev; /* EATA 2.0 rev., 'A' or 'B' or 'C' */ struct mssp sp[MAX_MAILBOXES]; /* Returned status for this board */ @@ -802,6 +808,8 @@ return SCSI_RESET_ERROR; } + HD(j)->retries = 0; + for (k = 0; k < MAX_TARGET; k++) HD(j)->target_reset[k] = TRUE; for (k = 0; k < MAX_TARGET; k++) HD(j)->target_time_out[k] = 0; @@ -1008,6 +1016,8 @@ HD(j)->target_time_out[SCpnt->target] = 0; + if (HD(j)->last_retried_pid == SCpnt->pid) HD(j)->retries = 0; + break; case ASST: /* Selection Time Out */ case 0x02: /* Command Time Out */ @@ -1020,17 +1030,23 @@ } break; + + /* Perform a limited number of internal retries */ case 0x03: /* SCSI Bus Reset Received */ case 0x04: /* Initial Controller Power-up */ - if (SCpnt->device->type != TYPE_TAPE) - status = DID_BUS_BUSY << 16; - else - status = DID_ERROR << 16; - for (k = 0; k < MAX_TARGET; k++) HD(j)->target_reset[k] = TRUE; + if (SCpnt->device->type != TYPE_TAPE + && HD(j)->retries < MAX_INTERNAL_RETRIES) { + status = DID_BUS_BUSY << 16; + HD(j)->retries++; + HD(j)->last_retried_pid = SCpnt->pid; + } + else + status = DID_ERROR << 16; + break; case 0x07: /* Bus Parity Error */ case 0x0c: /* Controller Ram Parity */ @@ -1058,7 +1074,7 @@ spp->adapter_status != ASST && HD(j)->iocount <= 1000) || do_trace) #endif - printk("%s: ihdlr, mbox %d, err 0x%x:%x,"\ + printk("%s: ihdlr, mbox %2d, err 0x%x:%x,"\ " target %d:%d, pid %ld, count %d.\n", BN(j), i, spp->adapter_status, spp->target_status, SCpnt->target, SCpnt->lun, SCpnt->pid, HD(j)->iocount); diff -ur --new-file old/linux/drivers/scsi/eata.h new/linux/drivers/scsi/eata.h --- old/linux/drivers/scsi/eata.h Thu May 2 06:48:53 1996 +++ new/linux/drivers/scsi/eata.h Wed Jul 10 07:05:27 1996 @@ -11,7 +11,7 @@ int eata2x_abort(Scsi_Cmnd *); int eata2x_reset(Scsi_Cmnd *, unsigned int); -#define EATA_VERSION "2.10.00" +#define EATA_VERSION "2.11.00" #define EATA { \ diff -ur --new-file old/linux/drivers/scsi/eata_dma.c new/linux/drivers/scsi/eata_dma.c --- old/linux/drivers/scsi/eata_dma.c Wed May 8 06:20:02 1996 +++ new/linux/drivers/scsi/eata_dma.c Wed Aug 14 09:21:03 1996 @@ -19,6 +19,7 @@ * versions of the boards * * -supports multiple HBAs with & without IRQ sharing * * -supports all SCSI channels on multi channel boards * + * -supports ix86 and MIPS, untested on ALPHA * * -needs identical IDs on all channels of a HBA * * -can be loaded as module * * -displays statistical and hardware information * @@ -57,7 +58,7 @@ * Jagdis who did a lot of testing and found quite a number * * of bugs during the development. * ************************************************************ - * last change: 95/05/05 OS: Linux 1.3.98 * + * last change: 96/08/13 OS: Linux 2.0.12 * ************************************************************/ /* Look in eata_dma.h for configuration and revision information */ @@ -77,6 +78,10 @@ #include #include #include +#include +#ifdef __mips__ +#include +#endif #include #include "scsi.h" #include "sd.h" @@ -244,13 +249,9 @@ struct eata_ccb *ccb; struct eata_sp *sp; uint base; - ulong flags; uint x; struct Scsi_Host *sh; - save_flags(flags); - cli(); - for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->next) { if (sh->irq != irq) continue; @@ -260,6 +261,9 @@ int_counter++; sp = &SD(sh)->sp; +#ifdef __mips__ + sys_cacheflush(sp, sizeof(struct eata_sp), 2); +#endif ccb = sp->ccb; if(ccb == NULL) { @@ -288,16 +292,17 @@ break; } - if (ccb->status == LOCKED) { - ccb->status = FREE; - eata_stat = inb(base + HA_RSTATUS); - printk("eata_dma: int_handler, freeing locked queueslot\n"); - DBG(DBG_INTR && DBG_DELAY, DELAY(1)); - break; + sp->EOC = FALSE; /* Clean out this flag */ + + if (ccb->status == LOCKED || ccb->status == RESET) { + ccb->status = FREE; + eata_stat = inb(base + HA_RSTATUS); + printk("eata_dma: int_handler, reseted command returned," + " freeing reseted queueslot\n"); + DBG(DBG_INTR && DBG_DELAY, DELAY(1)); + break; } - sp->EOC = FALSE; /* Clean out this flag */ - eata_stat = inb(base + HA_RSTATUS); DBG(DBG_INTR, printk("IRQ %d received, base %#.4x, pid %ld, " "target: %x, lun: %x, ea_s: %#.2x, hba_s: " @@ -306,11 +311,9 @@ switch (hba_stat) { case HA_NO_ERROR: /* NO Error */ - HD(cmd)->t_state[ccb->cp_channel][ccb->cp_id] = OK; if(HD(cmd)->do_latency == TRUE && ccb->timestamp) eata_latency_in(ccb, HD(cmd)); result = DID_OK << 16; - HD(cmd)->t_timeout[ccb->cp_channel][ccb->cp_id] = OK; break; case HA_ERR_SEL_TO: /* Selection Timeout */ case HA_ERR_CMD_TO: /* Command Timeout */ @@ -329,7 +332,6 @@ result = DID_ERROR << 16; for (i = 0; i < MAXTARGET; i++) - HD(cmd)->t_state[ccb->cp_channel][i] = RESET; DBG(DBG_STATUS, printk(KERN_DEBUG "scsi%d: cmd pid %ld " "returned with INIT_POWERUP\n", HD(cmd)->HBA_number, cmd->pid)); @@ -342,7 +344,6 @@ break; case HA_CP_RESET_NA: case HA_CP_RESET: - HD(cmd)->t_state[cmd->channel][cmd->target] = OK; HD(cmd)->resetlevel[cmd->channel] = 0; result = DID_RESET << 16; DBG(DBG_STATUS, printk(KERN_WARNING "scsi%d: reseted cmd " @@ -385,8 +386,7 @@ cmd->scsi_done(cmd); } } - restore_flags(flags); - + return; } @@ -398,17 +398,26 @@ if (--loop == 0) return(FALSE); + if(addr != (u32) NULL) + addr = virt_to_bus((void *)addr); + + /* + * This is overkill.....but the MIPSen seem to need this + * and it will be optimized away for i86 and ALPHA machines. + */ + flush_cache_all(); + /* And now the address in nice little byte chunks */ #ifdef __LITTLE_ENDIAN - outb( addr & 0x000000ff, base + HA_WDMAADDR); - outb((addr & 0x0000ff00) >> 8, base + HA_WDMAADDR + 1); - outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 2); - outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR + 3); + outb(addr, base + HA_WDMAADDR); + outb(addr >> 8, base + HA_WDMAADDR + 1); + outb(addr >> 16, base + HA_WDMAADDR + 2); + outb(addr >> 24, base + HA_WDMAADDR + 3); #else - outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR); - outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 1); - outb((addr & 0x0000ff00) >> 8, base + HA_WDMAADDR + 2); - outb((addr & 0x000000ff), base + HA_WDMAADDR + 3); + outb(addr >> 24, base + HA_WDMAADDR); + outb(addr >> 16, base + HA_WDMAADDR + 1); + outb(addr >> 8, base + HA_WDMAADDR + 2); + outb(addr, base + HA_WDMAADDR + 3); #endif outb(command, base + HA_WCOMMAND); return(TRUE); @@ -416,18 +425,27 @@ inline int eata_send_immediate(u32 base, u32 addr, u8 ifc, u8 code, u8 code2) { + if(addr != (u32) NULL) + addr = virt_to_bus((void *)addr); + + /* + * This is overkill.....but the MIPSen seem to need this + * and it will be optimized away for i86 and ALPHA machines. + */ + flush_cache_all(); + outb(0x0, base + HA_WDMAADDR - 1); if(addr){ #ifdef __LITTLE_ENDIAN - outb( addr & 0x000000ff, base + HA_WDMAADDR); - outb((addr & 0x0000ff00) >> 8, base + HA_WDMAADDR + 1); - outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 2); - outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR + 3); + outb(addr, base + HA_WDMAADDR); + outb(addr >> 8, base + HA_WDMAADDR + 1); + outb(addr >> 16, base + HA_WDMAADDR + 2); + outb(addr >> 24, base + HA_WDMAADDR + 3); #else - outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR); - outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 1); - outb((addr & 0x0000ff00) >> 8, base + HA_WDMAADDR + 2); - outb((addr & 0x000000ff), base + HA_WDMAADDR + 3); + outb(addr >> 24, base + HA_WDMAADDR); + outb(addr >> 16, base + HA_WDMAADDR + 1); + outb(addr >> 8, base + HA_WDMAADDR + 2); + outb(addr, base + HA_WDMAADDR + 3); #endif } else { outb(0x0, base + HA_WDMAADDR); @@ -491,6 +509,8 @@ memset(ccb, 0, sizeof(struct eata_ccb) - sizeof(struct eata_sg_list *)); ccb->status = USED; /* claim free slot */ + + restore_flags(flags); DBG(DBG_QUEUE, printk("eata_queue pid %ld, target: %x, lun: %x, y %d\n", cmd->pid, cmd->target, cmd->lun, y)); @@ -562,7 +582,7 @@ ccb->cp_statDMA = htonl(virt_to_bus(&(hd->sp))); ccb->cp_viraddr = ccb; /* This will be passed thru, so we don't need to - * convert it */ + * convert it */ ccb->cmd = cmd; cmd->host_scribble = (char *)&hd->ccb[y]; @@ -571,25 +591,26 @@ DBG(DBG_QUEUE && DBG_ABNORM, printk("eata_queue target %d, pid %ld, HBA busy, " "returning DID_BUS_BUSY\n",cmd->target, cmd->pid)); - done(cmd); ccb->status = FREE; - restore_flags(flags); + done(cmd); return(0); } DBG(DBG_QUEUE, printk("Queued base %#.4x pid: %ld target: %x lun: %x " "slot %d irq %d\n", (s32)sh->base, cmd->pid, cmd->target, cmd->lun, y, sh->irq)); DBG(DBG_QUEUE && DBG_DELAY, DELAY(1)); - restore_flags(flags); + return(0); } int eata_abort(Scsi_Cmnd * cmd) { - ulong loop = R_LIMIT; + ulong loop = HZ / 2; ulong flags; - + int x; + struct Scsi_Host *sh; + save_flags(flags); cli(); @@ -598,6 +619,15 @@ cmd->abort_reason)); DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); + /* Some interrupt controllers seem to loose interrupts */ + for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->next) { + if(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ) { + printk("eata_dma: scsi%d interrupt pending in eata_abort.\n" + " Calling interrupt handler.\n", sh->host_no); + eata_int_handler(sh->irq, 0, 0); + } + } + while (inb((u32)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY) { if (--loop == 0) { printk("eata_dma: abort, timeout error.\n"); @@ -634,12 +664,12 @@ int eata_reset(Scsi_Cmnd * cmd, unsigned int resetflags) { - ushort x, z; - ulong limit = 0; + uint x; ulong loop = loops_per_sec / 3; ulong flags; unchar success = FALSE; Scsi_Cmnd *sp; + struct Scsi_Host *sh; save_flags(flags); cli(); @@ -648,6 +678,14 @@ " reason %x\n", cmd->pid, cmd->target, cmd->lun, cmd->abort_reason)); + /* Some interrupt controllers seem to loose interrupts */ + for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->next) { + if(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ) { + printk("eata_dma: scsi%d interrupt pending in eata_reset.\n" + " Calling interrupt handler.\n", sh->host_no); + eata_int_handler(sh->irq, 0, 0); + } + } if (HD(cmd)->state == RESET) { printk("eata_reset: exit, already in reset.\n"); restore_flags(flags); @@ -663,30 +701,26 @@ return (SCSI_RESET_ERROR); } - for (x = 0; x < MAXCHANNEL; x++) { - for (z = 0; z < MAXTARGET; z++) { - HD(cmd)->t_state[x][z] = RESET; - HD(cmd)->t_timeout[x][z] = NO_TIMEOUT; - } - } - for (x = 0; x < cmd->host->can_queue; x++) { if (HD(cmd)->ccb[x].status == FREE) continue; - + if (HD(cmd)->ccb[x].status == LOCKED) { HD(cmd)->ccb[x].status = FREE; printk("eata_reset: locked slot %d forced free.\n", x); DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); continue; } + + sp = HD(cmd)->ccb[x].cmd; HD(cmd)->ccb[x].status = RESET; - printk("eata_reset: slot %d in reset, pid %ld.\n", x, sp->pid); - DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); if (sp == NULL) panic("eata_reset: slot %d, sp==NULL.\n", x); + + printk("eata_reset: slot %d in reset, pid %ld.\n", x, sp->pid); + DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); if (sp == cmd) @@ -697,18 +731,21 @@ inb((u32) (cmd->host->base) + HA_RSTATUS); /* This might cause trouble */ eata_send_command(0, (u32) cmd->host->base, EATA_CMD_RESET); - DBG(DBG_ABNORM, printk("eata_reset: board reset done, enabling interrupts.\n")); HD(cmd)->state = RESET; - DELAY(1); + DBG(DBG_ABNORM, printk("eata_reset: board reset done, enabling " + "interrupts.\n")); + + DELAY(2); /* In theorie we should get interrupts and set free all + * used queueslots */ - DBG(DBG_ABNORM, printk("eata_reset: interrupts disabled, loops %ld.\n", - limit)); + DBG(DBG_ABNORM, printk("eata_reset: interrupts disabled again.\n")); DBG(DBG_ABNORM && DBG_DELAY, DELAY(1)); for (x = 0; x < cmd->host->can_queue; x++) { - /* Skip slots already set free by interrupt */ + /* Skip slots already set free by interrupt and those that + * are still LOCKED from the last reset */ if (HD(cmd)->ccb[x].status != RESET) continue; @@ -750,8 +787,13 @@ Scsi_Device *device; int devcount = 0; int factor = 0; - - + +#if CRIPPLE_QUEUE + for(device = devicelist; device != NULL; device = device->next) { + if(device->host == host) + device->queue_depth = 2; + } +#else /* First we do a sample run go find out what we have */ for(device = devicelist; device != NULL; device = device->next) { if (device->host == host) { @@ -813,13 +855,24 @@ } else /* ISA forces us to limit the QS because of bounce buffers*/ device->queue_depth = 2; /* I know this is cruel */ + /* + * It showed that we need to set an upper limit of commands + * we can allow to queue for a single device on the bus. + * If we get above that limit, the broken midlevel SCSI code + * will produce bogus timeouts and aborts en masse. :-( + */ + if(device->queue_depth > UPPER_DEVICE_QUEUE_LIMIT) + device->queue_depth = UPPER_DEVICE_QUEUE_LIMIT; + printk(KERN_INFO "scsi%d: queue depth for target %d on channel %d " "set to %d\n", host->host_no, device->id, device->channel, device->queue_depth); } } +#endif } +#if CHECK_BLINK int check_blink_state(long base) { ushort loops = 10; @@ -841,6 +894,7 @@ else return (FALSE); } +#endif char * get_board_data(u32 base, u32 irq, u32 id) { @@ -848,7 +902,6 @@ struct eata_sp *sp; static char *buff; ulong i; - ulong limit = 0; cp = (struct eata_ccb *) scsi_init_malloc(sizeof(struct eata_ccb), GFP_ATOMIC | GFP_DMA); @@ -1287,11 +1340,14 @@ register_HBA(base, buf, tpnt, IS_EISA); } else printk("eata_dma: No valid IRQ. HBA removed from list\n"); - } else { + } +#if CHECK_BLINK + else { if (check_blink_state(base)) printk("HBA is in BLINK state. Consult your HBAs " "Manual to correct this.\n"); } +#endif /* Nothing found here so we take it from the list */ EISAbases[i] = 0; #if CHECKPAL @@ -1311,11 +1367,14 @@ if (get_conf_PIO(ISAbases[i],buf) == TRUE){ DBG(DBG_ISA, printk("Registering ISA HBA\n")); register_HBA(ISAbases[i], buf, tpnt, IS_ISA); - } else { + } +#if CHECK_BLINK + else { if (check_blink_state(ISAbases[i])) printk("HBA is in BLINK state. Consult your HBAs " "Manual to correct this.\n"); } +#endif ISAbases[i] = 0; } } @@ -1356,7 +1415,8 @@ (u16 *) & com_adr))) { if (!((com_adr & PCI_COMMAND_IO) && (com_adr & PCI_COMMAND_MASTER))) { - printk("eata_dma: find_PCI, HBA has IO or BUSMASTER mode disabled\n"); + printk("eata_dma: find_PCI, HBA has IO or" + " BUSMASTER mode disabled\n"); continue; } } else @@ -1366,7 +1426,8 @@ printk("eata_dma: find_PCI, DEVICECLASSID %x didn't match\n", rev_device); } else { - printk("eata_dma: find_PCI, error %x while reading PCI_CLASS_BASE\n", + printk("eata_dma: find_PCI, error %x while reading " + "PCI_CLASS_BASE\n", error); continue; } @@ -1411,10 +1472,13 @@ } else if ((base & 0x0fff) == 0x0c88) EISAbases[(base >> 12) & 0x0f] = 0; continue; /* break; */ - } else if (check_blink_state(base) == TRUE) { + } +#if CHECK_BLINK + else if (check_blink_state(base) == TRUE) { printk("eata_dma: HBA is in BLINK state.\n" "Consult your HBAs manual to correct this.\n"); } +#endif } } } else { @@ -1461,7 +1525,7 @@ for (i = 0; i <= MAXIRQ; i++) { /* Now that we know what we have, we */ if (reg_IRQ[i] >= 1){ /* exchange the interrupt handler which */ free_irq(i, NULL); /* we used for probing with the real one */ - request_irq(i, (void *)(eata_int_handler), SA_INTERRUPT, + request_irq(i, (void *)(eata_int_handler), SA_INTERRUPT|SA_SHIRQ, "eata_dma", NULL); } } diff -ur --new-file old/linux/drivers/scsi/eata_dma.h new/linux/drivers/scsi/eata_dma.h --- old/linux/drivers/scsi/eata_dma.h Mon May 6 06:34:20 1996 +++ new/linux/drivers/scsi/eata_dma.h Wed Aug 14 09:21:03 1996 @@ -4,7 +4,7 @@ * mike@i-Connect.Net * * neuffer@mail.uni-mainz.de * ********************************************************* -* last change: 96/05/05 * +* last change: 96/08/14 * ********************************************************/ #ifndef _EATA_DMA_H @@ -17,7 +17,7 @@ #define VER_MAJOR 2 #define VER_MINOR 5 -#define VER_SUB "8d" +#define VER_SUB "9a" /************************************************************************ @@ -25,7 +25,12 @@ ************************************************************************/ #define CHECKPAL 0 /* EISA pal checking on/off */ -#define NEWSTUFF 0 /* Some changes for ISA/EISA boards */ +#define CHECK_BLINK 1 /* Switch Blink state check off, might * + * be nessessary for some MIPS machines*/ +#define CRIPPLE_QUEUE 0 /* Only enable this if the interrupt + * controller on your motherboard is + * broken and you are experiencing + * massive interrupt losses */ /************************************************************************ * Debug options. * diff -ur --new-file old/linux/drivers/scsi/eata_dma_proc.c new/linux/drivers/scsi/eata_dma_proc.c --- old/linux/drivers/scsi/eata_dma_proc.c Fri Apr 12 08:49:41 1996 +++ new/linux/drivers/scsi/eata_dma_proc.c Thu Aug 1 14:43:04 1996 @@ -295,63 +295,66 @@ } if (pos > offset + length) goto stop_output; - - cmnd[0] = LOG_SENSE; - cmnd[1] = 0; - cmnd[2] = 0x32 + (3<<6); - cmnd[3] = 0; - cmnd[4] = 0; - cmnd[5] = 0; - cmnd[6] = 0; - cmnd[7] = 0x01; - cmnd[8] = 0x44; - cmnd[9] = 0; - - scmd.cmd_len = 10; - - /* - * Do the command and wait for it to finish. - */ - { - struct semaphore sem = MUTEX_LOCKED; - scmd.request.rq_status = RQ_SCSI_BUSY; - scmd.request.sem = &sem; - scsi_do_cmd (&scmd, cmnd, buff2, 0x144, - eata_scsi_done, 1 * HZ, 1); - down(&sem); - } - swap_statistics(buff2); - rhcs = (hst_cmd_stat *)(buff2 + 0x2c); - whcs = (hst_cmd_stat *)(buff2 + 0x8c); - - for (x = 0; x <= 11; x++) { - SD(HBA_ptr)->reads[x] += rhcs->sizes[x]; - SD(HBA_ptr)->writes[x] += whcs->sizes[x]; - SD(HBA_ptr)->reads[12] += rhcs->sizes[x]; - SD(HBA_ptr)->writes[12] += whcs->sizes[x]; - } - size = sprintf(buffer + len, "Host<->Disk command statistics:\n" - " Reads: Writes:\n"); - len += size; - pos = begin + len; - for (x = 0; x <= 10; x++) { - size = sprintf(buffer+len,"%5dk:%12u %12u\n", 1 << x, - SD(HBA_ptr)->reads[x], - SD(HBA_ptr)->writes[x]); + if(SD(HBA_ptr)->do_latency == FALSE) { + + cmnd[0] = LOG_SENSE; + cmnd[1] = 0; + cmnd[2] = 0x32 + (3<<6); + cmnd[3] = 0; + cmnd[4] = 0; + cmnd[5] = 0; + cmnd[6] = 0; + cmnd[7] = 0x01; + cmnd[8] = 0x44; + cmnd[9] = 0; + + scmd.cmd_len = 10; + + /* + * Do the command and wait for it to finish. + */ + { + struct semaphore sem = MUTEX_LOCKED; + scmd.request.rq_status = RQ_SCSI_BUSY; + scmd.request.sem = &sem; + scsi_do_cmd (&scmd, cmnd, buff2, 0x144, + eata_scsi_done, 1 * HZ, 1); + down(&sem); + } + + swap_statistics(buff2); + rhcs = (hst_cmd_stat *)(buff2 + 0x2c); + whcs = (hst_cmd_stat *)(buff2 + 0x8c); + + for (x = 0; x <= 11; x++) { + SD(HBA_ptr)->reads[x] += rhcs->sizes[x]; + SD(HBA_ptr)->writes[x] += whcs->sizes[x]; + SD(HBA_ptr)->reads[12] += rhcs->sizes[x]; + SD(HBA_ptr)->writes[12] += whcs->sizes[x]; + } + size = sprintf(buffer + len, "Host<->Disk command statistics:\n" + " Reads: Writes:\n"); + len += size; + pos = begin + len; + for (x = 0; x <= 10; x++) { + size = sprintf(buffer+len,"%5dk:%12u %12u\n", 1 << x, + SD(HBA_ptr)->reads[x], + SD(HBA_ptr)->writes[x]); + len += size; + pos = begin + len; + } + size = sprintf(buffer+len,">1024k:%12u %12u\n", + SD(HBA_ptr)->reads[11], + SD(HBA_ptr)->writes[11]); + len += size; + pos = begin + len; + size = sprintf(buffer+len,"Sum :%12u %12u\n", + SD(HBA_ptr)->reads[12], + SD(HBA_ptr)->writes[12]); len += size; pos = begin + len; } - size = sprintf(buffer+len,">1024k:%12u %12u\n", - SD(HBA_ptr)->reads[11], - SD(HBA_ptr)->writes[11]); - len += size; - pos = begin + len; - size = sprintf(buffer+len,"Sum :%12u %12u\n", - SD(HBA_ptr)->reads[12], - SD(HBA_ptr)->writes[12]); - len += size; - pos = begin + len; } if (pos < offset) { @@ -362,9 +365,11 @@ goto stop_output; if(SD(HBA_ptr)->do_latency == TRUE) { + int factor = 1024/HZ; size = sprintf(buffer + len, "Host Latency Command Statistics:\n" - "Current timer resolution: 10ms\n" - " Reads: Min:(ms) Max:(ms) Ave:(ms)\n"); + "Current timer resolution: %2dms\n" + " Reads: Min:(ms) Max:(ms) Ave:(ms)\n", + factor); len += size; pos = begin + len; for (x = 0; x <= 10; x++) { @@ -372,9 +377,9 @@ 1 << x, SD(HBA_ptr)->reads_lat[x][0], (SD(HBA_ptr)->reads_lat[x][1] == 0xffffffff) - ? 0:(SD(HBA_ptr)->reads_lat[x][1] * 10), - SD(HBA_ptr)->reads_lat[x][2] * 10, - SD(HBA_ptr)->reads_lat[x][3] * 10 / + ? 0:(SD(HBA_ptr)->reads_lat[x][1] * factor), + SD(HBA_ptr)->reads_lat[x][2] * factor, + SD(HBA_ptr)->reads_lat[x][3] * factor / ((SD(HBA_ptr)->reads_lat[x][0]) ? SD(HBA_ptr)->reads_lat[x][0]:1)); len += size; @@ -383,9 +388,9 @@ size = sprintf(buffer+len,">1024k:%12u %12u %12u %12u\n", SD(HBA_ptr)->reads_lat[11][0], (SD(HBA_ptr)->reads_lat[11][1] == 0xffffffff) - ? 0:(SD(HBA_ptr)->reads_lat[11][1] * 10), - SD(HBA_ptr)->reads_lat[11][2] * 10, - SD(HBA_ptr)->reads_lat[11][3] * 10 / + ? 0:(SD(HBA_ptr)->reads_lat[11][1] * factor), + SD(HBA_ptr)->reads_lat[11][2] * factor, + SD(HBA_ptr)->reads_lat[11][3] * factor / ((SD(HBA_ptr)->reads_lat[x][0]) ? SD(HBA_ptr)->reads_lat[x][0]:1)); len += size; @@ -407,9 +412,9 @@ 1 << x, SD(HBA_ptr)->writes_lat[x][0], (SD(HBA_ptr)->writes_lat[x][1] == 0xffffffff) - ? 0:(SD(HBA_ptr)->writes_lat[x][1] * 10), - SD(HBA_ptr)->writes_lat[x][2] * 10, - SD(HBA_ptr)->writes_lat[x][3] * 10 / + ? 0:(SD(HBA_ptr)->writes_lat[x][1] * factor), + SD(HBA_ptr)->writes_lat[x][2] * factor, + SD(HBA_ptr)->writes_lat[x][3] * factor / ((SD(HBA_ptr)->writes_lat[x][0]) ? SD(HBA_ptr)->writes_lat[x][0]:1)); len += size; @@ -418,9 +423,9 @@ size = sprintf(buffer+len,">1024k:%12u %12u %12u %12u\n", SD(HBA_ptr)->writes_lat[11][0], (SD(HBA_ptr)->writes_lat[11][1] == 0xffffffff) - ? 0:(SD(HBA_ptr)->writes_lat[x][1] * 10), - SD(HBA_ptr)->writes_lat[11][2] * 10, - SD(HBA_ptr)->writes_lat[11][3] * 10/ + ? 0:(SD(HBA_ptr)->writes_lat[x][1] * factor), + SD(HBA_ptr)->writes_lat[11][2] * factor, + SD(HBA_ptr)->writes_lat[11][3] * factor / ((SD(HBA_ptr)->writes_lat[x][0]) ? SD(HBA_ptr)->writes_lat[x][0]:1)); len += size; diff -ur --new-file old/linux/drivers/scsi/eata_generic.h new/linux/drivers/scsi/eata_generic.h --- old/linux/drivers/scsi/eata_generic.h Mon May 6 06:34:20 1996 +++ new/linux/drivers/scsi/eata_generic.h Wed Aug 14 09:21:03 1996 @@ -5,7 +5,7 @@ * mike@i-Connect.Net * * neuffer@mail.uni-mainz.de * ********************************************************* -* last change: 95/05/05 * +* last change: 96/08/14 * ********************************************************/ @@ -68,6 +68,12 @@ #define SG_SIZE 64 #define SG_SIZE_BIG 252 /* max. 8096 elements, 64k */ +#define UPPER_DEVICE_QUEUE_LIMIT 24 /* The limit we have to set for the + * device queue to keep the broken + * midlevel SCSI code from producing + * bogus timeouts + */ + #define TYPE_DISK_QUEUE 16 #define TYPE_TAPE_QUEUE 4 #define TYPE_ROM_QUEUE 4 @@ -90,10 +96,10 @@ #define CD(cmd) ((struct eata_ccb *)(cmd->host_scribble)) #define SD(host) ((hostdata *)&(host->hostdata)) -#define DELAY(x) { __u32 i; ulong flags; \ +#define DELAY(x) { ulong flags, i; \ save_flags(flags); sti(); \ i = jiffies + (x * HZ); \ - while (jiffies < i) barrier(); \ + while (jiffies < i); \ restore_flags(flags); } /*********************************************** @@ -130,6 +136,11 @@ #define EATA_COLD_BOOT_HBA 0x06 /* Only as a last resort */ #define EATA_FORCE_IO 0x07 +#define HA_CTRLREG 0x206 /* control register for HBA */ +#define HA_CTRL_DISINT 0x02 /* CTRLREG: disable interrupts */ +#define HA_CTRL_RESCPU 0x04 /* CTRLREG: reset processor */ +#define HA_CTRL_8HEADS 0x08 /* CTRLREG: set for drives with* + * >=8 heads (WD1003 rudimentary :-) */ #define HA_WCOMMAND 0x07 /* command register offset */ #define HA_WIFC 0x06 /* immediate command offset */ @@ -350,10 +361,6 @@ __u32 reads_lat[12][4]; __u32 writes_lat[12][4]; __u32 all_lat[4]; - /* state of Target (RESET,..) */ - __u8 t_state[MAXCHANNEL][MAXTARGET]; - /* timeouts on target */ - __u32 t_timeout[MAXCHANNEL][MAXTARGET]; __u8 resetlevel[MAXCHANNEL]; __u32 last_ccb; /* Last used ccb */ __u32 cplen; /* size of CP in words */ diff -ur --new-file old/linux/drivers/scsi/eata_pio.c new/linux/drivers/scsi/eata_pio.c --- old/linux/drivers/scsi/eata_pio.c Mon May 6 06:34:20 1996 +++ new/linux/drivers/scsi/eata_pio.c Thu Aug 1 14:43:04 1996 @@ -32,7 +32,7 @@ * Cambridge, MA 02139, USA. * * * ************************************************************ - * last change: 95/03/28 OS: Linux 1.3.80 * + * last change: 96/07/16 OS: Linux 2.0.8 * ************************************************************/ /* Look in eata_pio.h for configuration information */ @@ -79,21 +79,6 @@ static ulong int_counter = 0; static ulong queue_counter = 0; -void hprint(const char *str) -{ - char *hptr =(char *) 0x000b0000; - char *hptr2=(char *) 0x000b00a0; - char *hptr3=(char *) 0x000b0f00; - int z; - - memmove(hptr,hptr2,24*80*2); - for (z=0; zpid, cmd->target, cmd->lun, cmd->abort_reason)); @@ -471,11 +461,6 @@ return (SCSI_RESET_ERROR); } - for (z = 0; z < MAXTARGET; z++) { - HD(cmd)->t_state[0][z] = RESET; - HD(cmd)->t_timeout[0][z] = NO_TIMEOUT; - } - /* force all slots to be free */ for (x = 0; x < cmd->host->can_queue; x++) { @@ -495,7 +480,7 @@ } /* hard reset the HBA */ - outb((uint) cmd->host->base+HA_WCOMMAND, EATA_CMD_RESET); + outb(EATA_CMD_RESET, (uint) cmd->host->base+HA_WCOMMAND); DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: board reset done.\n")); HD(cmd)->state = RESET; @@ -586,7 +571,7 @@ int get_pio_conf_PIO(u32 base, struct get_conf *buf) { - ulong loop = R_LIMIT; + ulong loop = HZ/2; int z; ushort *p; @@ -603,14 +588,14 @@ printk(KERN_DEBUG "Issuing PIO READ CONFIG to HBA at %#x\n", base)); eata_pio_send_command(base, EATA_CMD_PIO_READ_CONFIG); - loop = R_LIMIT; + loop = HZ/2; for (p = (ushort *) buf; (long)p <= ((long)buf + (sizeof(struct get_conf) / 2)); p++) { while (!(inb(base + HA_RSTATUS) & HA_SDRQ)) if (--loop == 0) return (FALSE); - loop = R_LIMIT; + loop = HZ/2; *p = inw(base + HA_RDATA); } if (!(inb(base + HA_RSTATUS) & HA_SERROR)) { /* Error ? */ diff -ur --new-file old/linux/drivers/scsi/eata_pio.h new/linux/drivers/scsi/eata_pio.h --- old/linux/drivers/scsi/eata_pio.h Mon May 6 06:34:20 1996 +++ new/linux/drivers/scsi/eata_pio.h Thu Aug 1 14:43:04 1996 @@ -2,7 +2,7 @@ * Header file for eata_pio.c Linux EATA-PIO SCSI driver * * (c) 1993-96 Michael Neuffer * ********************************************************* -* last change: 95/06/21 * +* last change: 96/05/05 * ********************************************************/ diff -ur --new-file old/linux/drivers/scsi/fdomain.c new/linux/drivers/scsi/fdomain.c --- old/linux/drivers/scsi/fdomain.c Mon May 6 11:26:11 1996 +++ new/linux/drivers/scsi/fdomain.c Fri Aug 9 09:43:24 1996 @@ -1,10 +1,10 @@ /* fdomain.c -- Future Domain TMC-16x0 SCSI driver * Created: Sun May 3 18:53:19 1992 by faith@cs.unc.edu - * Revised: Thu Apr 4 20:44:47 1996 by r.faith@ieee.org + * Revised: Thu Aug 8 14:58:51 1996 by r.faith@ieee.org * Author: Rickard E. Faith, faith@cs.unc.edu * Copyright 1992, 1993, 1994, 1995, 1996 Rickard E. Faith * - * $Id: fdomain.c,v 5.41 1996/04/05 04:22:25 root Exp $ + * $Id: fdomain.c,v 5.44 1996/08/08 18:58:53 root Exp $ * 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 @@ -104,6 +104,7 @@ 1.3.34 5.39 12 Oct 1995 V3.60 BIOS; /proc 1.3.72 5.39 8 Feb 1996 Adaptec AHA-2920 board 1.3.85 5.41 4 Apr 1996 + 2.0.12 5.44 8 Aug 1996 Use ID 7 for all PCI cards @@ -275,7 +276,7 @@ S_IFDIR | S_IRUGO | S_IXUGO, 2 }; -#define VERSION "$Revision: 5.41 $" +#define VERSION "$Revision: 5.44 $" /* START OF USER DEFINABLE OPTIONS */ @@ -580,8 +581,8 @@ /* Try to toggle 32-bit mode. This only works on an 18c30 chip. (User reports - say that this doesn't work at all, so - we'll use the other method.) */ + say this works, so we should switch to + it in the near future.) */ outb( 0x80, port + IO_Control ); if ((inb( port + Configuration2 ) & 0x80) == 0x80) { @@ -1018,7 +1019,7 @@ tpnt->this_id = (this_id & 0x07); adapter_mask = (1 << tpnt->this_id); } else { - if ((bios_major == 3 && bios_minor >= 2) || bios_major < 0) { + if (PCI_bus || (bios_major == 3 && bios_minor >= 2) || bios_major < 0) { tpnt->this_id = 7; adapter_mask = 0x80; } else { @@ -1246,7 +1247,7 @@ #endif #if ERRORS_ONLY if (!target) { - if (chip == tmc18c30 && !flag) /* Skip first failure for 18C30 chips. */ + if (!flag) /* Skip first failure for all chips. */ ++flag; else printk( "fdomain: Selection failed\n" ); @@ -1394,7 +1395,9 @@ printk( "Status = %x, ", current_SC->SCp.Status ); #endif #if ERRORS_ONLY - if (current_SC->SCp.Status && current_SC->SCp.Status != 2) { + if (current_SC->SCp.Status + && current_SC->SCp.Status != 2 + && current_SC->SCp.Status != 8) { printk( "fdomain: target = %d, command = %x, status = %x\n", current_SC->target, current_SC->cmnd[0], @@ -1666,7 +1669,7 @@ qualifier = (unsigned char)(*((char *)current_SC->request_buffer + 13)); - if (!(key == UNIT_ATTENTION && (code == 0x29 || !code)) + if (key != UNIT_ATTENTION && !(key == NOT_READY && code == 0x04 && (!qualifier || qualifier == 0x02 || qualifier == 0x01)) diff -ur --new-file old/linux/drivers/scsi/hosts.c new/linux/drivers/scsi/hosts.c --- old/linux/drivers/scsi/hosts.c Fri Jun 7 10:53:09 1996 +++ new/linux/drivers/scsi/hosts.c Wed Aug 7 11:31:21 1996 @@ -133,6 +133,10 @@ #include "53c7,8xx.h" #endif +#ifdef CONFIG_SCSI_NCR53C8XX +#include "ncr53c8xx.h" +#endif + #ifdef CONFIG_SCSI_ULTRASTOR #include "ultrastor.h" #endif @@ -257,6 +261,9 @@ #ifdef CONFIG_SCSI_QLOGIC_FAS QLOGICFAS, #endif +#ifdef CONFIG_SCSI_QLOGIC_ISP + QLOGICISP, +#endif #ifdef CONFIG_SCSI_PAS16 MV_PAS16, #endif @@ -272,6 +279,9 @@ #ifdef CONFIG_SCSI_NCR53C7xx NCR53c7xx, #endif +#ifdef CONFIG_SCSI_NCR53C8XX + NCR53C8XX, +#endif #ifdef CONFIG_SCSI_EATA_DMA EATA_DMA, #endif @@ -286,9 +296,6 @@ #endif #ifdef CONFIG_SCSI_AM53C974 AM53C974, -#endif -#ifdef CONFIG_SCSI_QLOGIC_ISP - QLOGICISP, #endif #ifdef CONFIG_SCSI_PPA PPA, diff -ur --new-file old/linux/drivers/scsi/hosts.h new/linux/drivers/scsi/hosts.h --- old/linux/drivers/scsi/hosts.h Sat May 18 21:19:00 1996 +++ new/linux/drivers/scsi/hosts.h Mon Jul 1 19:06:05 1996 @@ -244,7 +244,7 @@ unsigned short extra_bytes; volatile unsigned char host_busy; char host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */ - int last_reset; + unsigned long last_reset; struct wait_queue *host_wait; Scsi_Cmnd *host_queue; Scsi_Host_Template * hostt; diff -ur --new-file old/linux/drivers/scsi/ncr53c8xx.c new/linux/drivers/scsi/ncr53c8xx.c --- old/linux/drivers/scsi/ncr53c8xx.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/scsi/ncr53c8xx.c Mon Aug 12 10:45:46 1996 @@ -0,0 +1,8225 @@ +/****************************************************************************** +** Device driver for the PCI-SCSI NCR538XX controller family. +** +** Copyright (C) 1994 Wolfgang Stanglmeier +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +**----------------------------------------------------------------------------- +** +** This driver has been ported to Linux from the FreeBSD NCR53C8XX driver +** and is currently maintained by +** +** Gerard Roudier +** +** Being given that this driver originates from the FreeBSD version, and +** in order to keep synergy on both, any suggested enhancements and corrections +** received on Linux are automatically a potential candidate for the FreeBSD +** version. +** +** The original driver has been written for 386bsd and FreeBSD by +** Wolfgang Stanglmeier +** Stefan Esser +** +** And has been ported to NetBSD by +** Charles M. Hannum +** +******************************************************************************* +*/ + +/* +** 21 July 1996, version 1.12b +** +** Supported SCSI-II features: +** Synchronous negotiation +** Wide negotiation (depends on the NCR Chip) +** Enable disconnection +** Tagged command queuing +** Parity checking +** Etc... +** +** Supported NCR chips: +** 53C810 (NCR BIOS in flash-bios required) +** 53C815 (~53C810 with on board rom BIOS) +** 53C820 (Wide, NCR BIOS in flash bios required) +** 53C825 (Wide, ~53C820 with on board rom BIOS) +** +** Other features: +** Memory mapped IO (linux-1.3.X only) +** Module +** Shared IRQ (since linux-1.3.72) +*/ + +#define SCSI_NCR_DEBUG +#define SCSI_NCR_DEBUG_FLAGS (0) + +#define NCR_DATE "pl23 95/09/07" + +#define NCR_VERSION (2) + +#define NCR_GETCC_WITHMSG + +/*========================================================== +** +** Include files +** +**========================================================== +*/ + +#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) + +#ifdef MODULE +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0) +#include "linux/blk.h" +#else +#include "../block/blk.h" +#endif + +#include "scsi.h" +#include "hosts.h" +#include "constants.h" +#include "sd.h" + +#include + +/* +** Define the BSD style u_int32 type +*/ +typedef u32 u_int32; + +#include "ncr53c8xx.h" + +/*========================================================== +** +** Configuration and Debugging +** +**========================================================== +*/ + +/* +** Proc info and user command support +*/ + +#ifdef SCSI_NCR_PROC_INFO_SUPPORT +#define SCSI_NCR_PROFILE +#define SCSI_NCR_USER_COMMAND +#endif + +/* +** SCSI address of this device. +** The boot routines should have set it. +** If not, use this. +*/ + +#ifndef SCSI_NCR_MYADDR +#define SCSI_NCR_MYADDR (7) +#endif + +/* +** The maximal synchronous frequency in kHz. +** (0=asynchronous) +*/ + +#ifndef SCSI_NCR_MAX_SYNC +#define SCSI_NCR_MAX_SYNC (10000) +#endif + +/* +** The maximal bus with (in log2 byte) +** (0=8 bit, 1=16 bit) +*/ + +#ifndef SCSI_NCR_MAX_WIDE +#define SCSI_NCR_MAX_WIDE (1) +#endif + +/* +** The maximum number of tags per logic unit. +** Used only for disk devices that support tags. +*/ + +#ifndef SCSI_NCR_MAX_TAGS +#define SCSI_NCR_MAX_TAGS (4) +#endif + +/*========================================================== +** +** Configuration and Debugging +** +**========================================================== +*/ + +/* +** Number of targets supported by the driver. +** n permits target numbers 0..n-1. +** Default is 7, meaning targets #0..#6. +** #7 .. is myself. +*/ + +#ifdef SCSI_NCR_MAX_TARGET +#define MAX_TARGET (SCSI_NCR_MAX_TARGET) +#else +#define MAX_TARGET (16) +#endif + +/* +** Number of logic units supported by the driver. +** n enables logic unit numbers 0..n-1. +** The common SCSI devices require only +** one lun, so take 1 as the default. +*/ + +#ifdef SCSI_NCR_MAX_LUN +#define MAX_LUN SCSI_NCR_MAX_LUN +#else +#define MAX_LUN (1) +#endif + + +/* +** The maximum number of jobs scheduled for starting. +** There should be one slot per target, and one slot +** for each tag of each target in use. +** The calculation below is actually quite silly ... +*/ + +#ifdef SCSI_NCR_CAN_QUEUE +#define MAX_START (SCSI_NCR_CAN_QUEUE + 4) +#else +#define MAX_START (MAX_TARGET + 7 * SCSI_NCR_MAX_TAGS) +#endif + +/* +** The maximum number of segments a transfer is split into. +*/ + +#define MAX_SCATTER (SCSI_NCR_MAX_SCATTER) + +/* +** The maximum transfer length (should be >= 64k). +** MUST NOT be greater than (MAX_SCATTER-1) * NBPG. +*/ + +#if 0 +#define MAX_SIZE ((MAX_SCATTER-1) * (long) NBPG) +#endif + +/* +** other +*/ + +#define NCR_SNOOP_TIMEOUT (1000000) + +#if defined(SCSI_NCR_IOMAPPED) || defined(__alpha__) +#define NCR_IOMAPPED +#endif + +/*========================================================== +** +** Defines for Linux. +** +** Linux and Bsd kernel functions are quite different. +** These defines allow a minimum change of the original +** code. +** +**========================================================== +*/ + + /* + ** Obvious definitions + */ + +#define printf printk +#define u_char unsigned char +#define u_short unsigned short +#define u_int unsigned int +#define u_long unsigned long + +typedef u_long vm_offset_t; +typedef int vm_size_t; + +#define bcopy(s, d, n) memcpy((d), (s), (n)) +#define bzero(d, n) memset((d), 0, (n)) + +#ifndef offsetof +#define offsetof(t, m) ((size_t) (&((t *)0)->m)) +#endif + +/* +** Address translation +** +** On Linux 1.3.X, virt_to_bus() must be used to translate +** virtual memory addresses of the kernel data segment into +** IO bus adresses. +** On i386 architecture, IO bus addresses match the physical +** addresses. But on Alpha architecture they are different. +** In the original Bsd driver, vtophys() is called to translate +** data addresses to IO bus addresses. In order to minimize +** change, I decide to define vtophys() as virt_to_bus(). +*/ + +#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0) +#define vtophys(p) virt_to_bus(p) + +/* +** Memory mapped IO +** +** Linux 1.3.X allow to remap physical pages addresses greater than +** the highest physical memory address to kernel virtual pages. +** We must use vremap() to map the page and vfree() to unmap it. +** The memory base of ncr chips is set by the bios at a high physical +** address. Also we can map it, and MMIO is possible. +*/ + +static inline vm_offset_t remap_pci_mem(u_long base, u_long size) +{ + u_long page_base = ((u_long) base) & PAGE_MASK; + u_long page_offs = ((u_long) base) - page_base; + u_long page_remapped = (u_long) vremap(page_base, page_offs+size); + + return (vm_offset_t) (page_remapped ? (page_remapped + page_offs) : 0UL); +} +static inline void unmap_pci_mem(vm_offset_t vaddr, u_long size) +{ + if (vaddr) vfree((void *) (vaddr & PAGE_MASK)); +} + +#else + +/* +** Linux 1.2.X assumes that addresses (virtual, physical, bus) +** are the same. +** +** I have not found how to do MMIO. It seems that only processes can +** map high physical pages to virtual (Xservers can do MMIO). +*/ + +#define vtophys(p) ((u_long) (p)) +#endif + +static void DELAY(long us) +{ + for (;us>1000;us-=1000) udelay(1000); + if (us) udelay(us); +} + +/* +** Internal data structure allocation. +** +** Linux scsi memory poor pool is adjusted for the need of +** middle-level scsi driver. +** We allocate our control blocks in the kernel memory pool +** to avoid scsi pool shortage. +** I notice that kmalloc() returns NULL during host attach under +** Linux 1.2.13. But this ncr driver is reliable enough to +** accomodate with this joke. +**/ + +static inline void *m_alloc(int size) +{ + void *ptr = (void *) kmalloc(size, GFP_ATOMIC); + if (((unsigned long) ptr) & 3) + panic("ncr53c8xx: kmalloc returns misaligned address %lx\n", (unsigned long) ptr); + return ptr; +} + +static inline void m_free(void *ptr, int size) + { kfree(ptr); } + +/* +** Transfer direction +** +** The middle scsi driver of Linux does not provide the transfer +** direction in the command structure. +** FreeBsd ncr driver require this information. +** +** I spent some hours to read the scsi2 documentation to see if +** it was possible to deduce the direction of transfer from the opcode +** of the command. It seems that it's OK. +** guess_xfer_direction() seems to work. If it's wrong we will +** get a phase mismatch on some opcode. +*/ + +#define XferNone 0 +#define XferIn 1 +#define XferOut 2 +#define XferBoth 3 +static int guess_xfer_direction(int opcode); + +/* +** Head of list of NCR boards +** +** Host is retrieved by its irq level. +*/ + +static struct Scsi_Host *first_host = NULL; +static Scsi_Host_Template *the_template = NULL; + + +/* +** /proc directory entry and proc_info function +*/ + +#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0) +struct proc_dir_entry proc_scsi_ncr53c8xx = { + PROC_SCSI_NCR53C8XX, 9, "ncr53c8xx", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; +# ifdef SCSI_NCR_PROC_INFO_SUPPORT +int ncr53c8xx_proc_info(char *buffer, char **start, off_t offset, + int length, int hostno, int func); +# endif +#endif + +/* +** Table of target capabilities. +** +** This bitmap is anded with the byte 7 of inquiry data on completion of +** INQUIRY command. +** The driver never see zeroed bits and will ignore the corresponding +** capabilities of the target. +*/ + +static struct { + unsigned char and_map[MAX_TARGET]; +} target_capabilities[SCSI_NCR_MAX_HOST] = { NCR53C8XX_TARGET_CAPABILITIES }; + + +/* +** Other Linux definitions +*/ + +#define ScsiResult(host_code, scsi_code) (((host_code) << 16) + ((scsi_code) & 0x7f)) + +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,0,0) +static void ncr53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_device *devlist); +#endif + +#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70) +static void ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs); +#else +static void ncr53c8xx_intr(int irq, struct pt_regs * regs); +#endif + +static void ncr53c8xx_timeout(unsigned long np); + +#define bootverbose 1 + +/*========================================================== +** +** Debugging tags +** +**========================================================== +*/ + +#define DEBUG_ALLOC (0x0001) +#define DEBUG_PHASE (0x0002) +#define DEBUG_POLL (0x0004) +#define DEBUG_QUEUE (0x0008) +#define DEBUG_RESULT (0x0010) +#define DEBUG_SCATTER (0x0020) +#define DEBUG_SCRIPT (0x0040) +#define DEBUG_TINY (0x0080) +#define DEBUG_TIMING (0x0100) +#define DEBUG_NEGO (0x0200) +#define DEBUG_TAGS (0x0400) +#define DEBUG_FREEZE (0x0800) +#define DEBUG_RESTART (0x1000) + +/* +** Enable/Disable debug messages. +** Can be changed at runtime too. +*/ + +#ifdef SCSI_NCR_DEBUG + #define DEBUG_FLAGS ncr_debug +#else + #define DEBUG_FLAGS SCSI_NCR_DEBUG_FLAGS +#endif + + + +/*========================================================== +** +** assert () +** +**========================================================== +** +** modified copy from 386bsd:/usr/include/sys/assert.h +** +**---------------------------------------------------------- +*/ + +#define assert(expression) { \ + if (!(expression)) { \ + (void)printf(\ + "assertion \"%s\" failed: file \"%s\", line %d\n", \ + #expression, \ + __FILE__, __LINE__); \ + } \ +} + +/*========================================================== +** +** Access to the controller chip. +** +** If NCR_IOMAPPED is defined, only IO are used by the driver. +** Else, we begins initialisations by using MMIO. +** If cache test fails, we retry using IO mapped. +** The flag "use_mmio" in the ncb structure is set to 1 if +** mmio is possible. +** +**========================================================== +*/ + +/* +** IO mapped input / ouput +*/ + +#define IOM_INB(r) inb (np->port + offsetof(struct ncr_reg, r)) +#define IOM_INB_OFF(o) inb (np->port + (o)) +#define IOM_INW(r) inw (np->port + offsetof(struct ncr_reg, r)) +#define IOM_INL(r) inl (np->port + offsetof(struct ncr_reg, r)) +#define IOM_INL_OFF(o) inl (np->port + (o)) + +#define IOM_OUTB(r, val) outb ((val), np->port+offsetof(struct ncr_reg,r)) +#define IOM_OUTW(r, val) outw ((val), np->port+offsetof(struct ncr_reg,r)) +#define IOM_OUTL(r, val) outl ((val), np->port+offsetof(struct ncr_reg,r)) +#define IOM_OUTL_OFF(o, val) outl ((val), np->port + (o)) + +/* +** MEMORY mapped IO input / output +*/ + +#define MMIO_INB(r) readb(&np->reg_remapped->r) +#define MMIO_INB_OFF(o) readb((char *)np->reg_remapped + (o)) +#define MMIO_INW(r) readw(&np->reg_remapped->r) +#define MMIO_INL(r) readl(&np->reg_remapped->r) +#define MMIO_INL_OFF(o) readl((char *)np->reg_remapped + (o)) + +#define MMIO_OUTB(r, val) writeb((val), &np->reg_remapped->r) +#define MMIO_OUTW(r, val) writew((val), &np->reg_remapped->r) +#define MMIO_OUTL(r, val) writel((val), &np->reg_remapped->r) +#define MMIO_OUTL_OFF(o, val) writel((val), (char *)np->reg_remapped + (o)) + +/* +** IO mapped only input / output +*/ + +#ifdef NCR_IOMAPPED + +#define INB(r) IOM_INB(r) +#define INB_OFF(o) IOM_INB_OFF(o) +#define INW(r) IOM_INW(r) +#define INL(r) IOM_INL(r) +#define INL_OFF(r) IOM_INL_OFF(o) + +#define OUTB(r, val) IOM_OUTB(r, val) +#define OUTW(r, val) IOM_OUTW(r, val) +#define OUTL(r, val) IOM_OUTL(r, val) +#define OUTL_OFF(o, val) IOM_OUTL_OFF(o, val) + +/* +** IO mapped or MEMORY mapped depending on flag "use_mmio" +*/ + +#else + +#define INB(r) (np->use_mmio ? MMIO_INB(r) : IOM_INB(r)) +#define INB_OFF(o) (np->use_mmio ? MMIO_INB_OFF(o) : IOM_INB_OFF(o)) +#define INW(r) (np->use_mmio ? MMIO_INW(r) : IOM_INW(r)) +#define INL(r) (np->use_mmio ? MMIO_INL(r) : IOM_INL(r)) +#define INL_OFF(o) (np->use_mmio ? MMIO_INL_OFF(o) : IOM_INL_OFF(o)) + +#define OUTB(r, val) (np->use_mmio ? MMIO_OUTB(r, val) : IOM_OUTB(r, val)) +#define OUTW(r, val) (np->use_mmio ? MMIO_OUTW(r, val) : IOM_OUTW(r, val)) +#define OUTL(r, val) (np->use_mmio ? MMIO_OUTL(r, val) : IOM_OUTL(r, val)) +#define OUTL_OFF(o, val) (np->use_mmio ? MMIO_OUTL_OFF(o, val) : IOM_OUTL_OFF(o, val)) + +#endif + +/*========================================================== +** +** Command control block states. +** +**========================================================== +*/ + +#define HS_IDLE (0) +#define HS_BUSY (1) +#define HS_NEGOTIATE (2) /* sync/wide data transfer*/ +#define HS_DISCONNECT (3) /* Disconnected by target */ + +#define HS_COMPLETE (4) +#define HS_SEL_TIMEOUT (5) /* Selection timeout */ +#define HS_RESET (6) /* SCSI reset */ +#define HS_ABORTED (7) /* Transfer aborted */ +#define HS_TIMEOUT (8) /* Software timeout */ +#define HS_FAIL (9) /* SCSI or PCI bus errors */ +#define HS_UNEXPECTED (10) /* Unexpected disconnect */ + +#define HS_DONEMASK (0xfc) + +/*========================================================== +** +** Software Interrupt Codes +** +**========================================================== +*/ + +#define SIR_SENSE_RESTART (1) +#define SIR_SENSE_FAILED (2) +#define SIR_STALL_RESTART (3) +#define SIR_STALL_QUEUE (4) +#define SIR_NEGO_SYNC (5) +#define SIR_NEGO_WIDE (6) +#define SIR_NEGO_FAILED (7) +#define SIR_NEGO_PROTO (8) +#define SIR_REJECT_RECEIVED (9) +#define SIR_REJECT_SENT (10) +#define SIR_IGN_RESIDUE (11) +#define SIR_MISSING_SAVE (12) +#define SIR_MAX (12) + +/*========================================================== +** +** Extended error codes. +** xerr_status field of struct ccb. +** +**========================================================== +*/ + +#define XE_OK (0) +#define XE_EXTRA_DATA (1) /* unexpected data phase */ +#define XE_BAD_PHASE (2) /* illegal phase (4/5) */ + +/*========================================================== +** +** Negotiation status. +** nego_status field of struct ccb. +** +**========================================================== +*/ + +#define NS_SYNC (1) +#define NS_WIDE (2) + +/*========================================================== +** +** "Special features" of targets. +** quirks field of struct tcb. +** actualquirks field of struct ccb. +** +**========================================================== +*/ + +#define QUIRK_AUTOSAVE (0x01) +#define QUIRK_NOMSG (0x02) +#define QUIRK_NOSYNC (0x10) +#define QUIRK_NOWIDE16 (0x20) +#define QUIRK_UPDATE (0x80) + +/*========================================================== +** +** Capability bits in Inquire response byte 7. +** +**========================================================== +*/ + +#define INQ7_QUEUE (0x02) +#define INQ7_SYNC (0x10) +#define INQ7_WIDE16 (0x20) + +/*========================================================== +** +** Misc. +** +**========================================================== +*/ + +#define CCB_MAGIC (0xf2691ad2) +#define MAX_TAGS (16) /* hard limit */ + +/*========================================================== +** +** Declaration of structs. +** +**========================================================== +*/ + +struct tcb; +struct lcb; +struct ccb; +struct ncb; +struct script; + +typedef struct ncb * ncb_p; +typedef struct tcb * tcb_p; +typedef struct lcb * lcb_p; +typedef struct ccb * ccb_p; + +struct link { + ncrcmd l_cmd; + ncrcmd l_paddr; +}; + +struct usrcmd { + u_long target; + u_long lun; + u_long data; + u_long cmd; +}; + +#define UC_SETSYNC 10 +#define UC_SETTAGS 11 +#define UC_SETDEBUG 12 +#define UC_SETORDER 13 +#define UC_SETWIDE 14 +#define UC_SETFLAG 15 +#define UC_CLEARPROF 16 + +#define UF_TRACE (0x01) + +/*--------------------------------------- +** +** Timestamps for profiling +** +**--------------------------------------- +*/ + +struct tstamp { + u_long start; + u_long end; + u_long select; + u_long command; + u_long data; + u_long status; + u_long disconnect; + u_long reselect; +}; + +/* +** profiling data (per device) +*/ + +struct profile { + u_long num_trans; + u_long num_kbytes; + u_long rest_bytes; + u_long num_disc; + u_long num_break; + u_long num_int; + u_long num_fly; + u_long ms_setup; + u_long ms_data; + u_long ms_disc; + u_long ms_post; +}; + +/*========================================================== +** +** Declaration of structs: target control block +** +**========================================================== +*/ + +struct tcb { + /* + ** during reselection the ncr jumps to this point + ** with SFBR set to the encoded target number + ** with bit 7 set. + ** if it's not this target, jump to the next. + ** + ** JUMP IF (SFBR != #target#) + ** @(next tcb) + */ + + struct link jump_tcb; + + /* + ** load the actual values for the sxfer and the scntl3 + ** register (sync/wide mode). + ** + ** SCR_COPY (1); + ** @(sval field of this tcb) + ** @(sxfer register) + ** SCR_COPY (1); + ** @(wval field of this tcb) + ** @(scntl3 register) + */ + + ncrcmd getscr[6]; + + /* + ** if next message is "identify" + ** then load the message to SFBR, + ** else load 0 to SFBR. + ** + ** CALL + ** + */ + + struct link call_lun; + + /* + ** now look for the right lun. + ** + ** JUMP + ** @(first ccb of this lun) + */ + + struct link jump_lcb; + + /* + ** pointer to interrupted getcc ccb + */ + + ccb_p hold_cp; + + /* + ** statistical data + */ + + u_long transfers; + u_long bytes; + + /* + ** user settable limits for sync transfer + ** and tagged commands. + */ + + u_char usrsync; + u_char usrtags; + u_char usrwide; + u_char usrflag; + + /* + ** negotiation of wide and synch transfer. + ** device quirks. + */ + +/*0*/ u_char minsync; +/*1*/ u_char sval; +/*2*/ u_short period; +/*0*/ u_char maxoffs; + +/*1*/ u_char quirks; + +/*2*/ u_char widedone; +/*3*/ u_char wval; + /* + ** inquire data + */ +#define MAX_INQUIRE 36 + u_char inqdata[MAX_INQUIRE]; + + /* + ** the lcb's of this tcb + */ + + lcb_p lp[MAX_LUN]; +}; + +/*========================================================== +** +** Declaration of structs: lun control block +** +**========================================================== +*/ + +struct lcb { + /* + ** during reselection the ncr jumps to this point + ** with SFBR set to the "Identify" message. + ** if it's not this lun, jump to the next. + ** + ** JUMP IF (SFBR != #lun#) + ** @(next lcb of this target) + */ + + struct link jump_lcb; + + /* + ** if next message is "simple tag", + ** then load the tag to SFBR, + ** else load 0 to SFBR. + ** + ** CALL + ** + */ + + struct link call_tag; + + /* + ** now look for the right ccb. + ** + ** JUMP + ** @(first ccb of this lun) + */ + + struct link jump_ccb; + + /* + ** start of the ccb chain + */ + + ccb_p next_ccb; + + /* + ** Control of tagged queueing + */ + + u_char reqccbs; + u_char actccbs; + u_char reqlink; + u_char actlink; + u_char usetags; + u_char lasttag; + + /*----------------------------------------------- + ** Flag to force M_ORDERED_TAG on next command + ** in order to avoid spurious timeout when + ** M_SIMPLE_TAG is used for all operations. + **----------------------------------------------- + */ + u_char force_ordered_tag; +#define NCR_TIMEOUT_INCREASE (5*HZ) +}; + +/*========================================================== +** +** Declaration of structs: COMMAND control block +** +**========================================================== +** +** This substructure is copied from the ccb to a +** global address after selection (or reselection) +** and copied back before disconnect. +** +** These fields are accessible to the script processor. +** +**---------------------------------------------------------- +*/ + +struct head { + /* + ** Execution of a ccb starts at this point. + ** It's a jump to the "SELECT" label + ** of the script. + ** + ** After successful selection the script + ** processor overwrites it with a jump to + ** the IDLE label of the script. + */ + + struct link launch; + + /* + ** Saved data pointer. + ** Points to the position in the script + ** responsible for the actual transfer + ** of data. + ** It's written after reception of a + ** "SAVE_DATA_POINTER" message. + ** The goalpointer points after + ** the last transfer command. + */ + + u_long savep; + u_long lastp; + u_long goalp; + + /* + ** The virtual address of the ccb + ** containing this header. + */ + + ccb_p cp; + + /* + ** space for some timestamps to gather + ** profiling data about devices and this driver. + */ + + struct tstamp stamp; + + /* + ** status fields. + */ + + u_char status[8]; +}; + +/* +** The status bytes are used by the host and the script processor. +** +** The first four byte are copied to the scratchb register +** (declared as scr0..scr3 in ncr_reg.h) just after the select/reselect, +** and copied back just after disconnecting. +** Inside the script the XX_REG are used. +** +** The last four bytes are used inside the script by "COPY" commands. +** Because source and destination must have the same alignment +** in a longword, the fields HAVE to be at the choosen offsets. +** xerr_st (4) 0 (0x34) scratcha +** sync_st (5) 1 (0x05) sxfer +** wide_st (7) 3 (0x03) scntl3 +*/ + +/* +** First four bytes (script) +*/ +#define QU_REG scr0 +#define HS_REG scr1 +#define HS_PRT nc_scr1 +#define SS_REG scr2 +#define PS_REG scr3 + +/* +** First four bytes (host) +*/ +#define actualquirks phys.header.status[0] +#define host_status phys.header.status[1] +#define scsi_status phys.header.status[2] +#define parity_status phys.header.status[3] + +/* +** Last four bytes (script) +*/ +#define xerr_st header.status[4] /* MUST be ==0 mod 4 */ +#define sync_st header.status[5] /* MUST be ==1 mod 4 */ +#define nego_st header.status[6] +#define wide_st header.status[7] /* MUST be ==3 mod 4 */ + +/* +** Last four bytes (host) +*/ +#define xerr_status phys.xerr_st +#define sync_status phys.sync_st +#define nego_status phys.nego_st +#define wide_status phys.wide_st + +/*========================================================== +** +** Declaration of structs: Data structure block +** +**========================================================== +** +** During execution of a ccb by the script processor, +** the DSA (data structure address) register points +** to this substructure of the ccb. +** This substructure contains the header with +** the script-processor-changable data and +** data blocks for the indirect move commands. +** +**---------------------------------------------------------- +*/ + +struct dsb { + + /* + ** Header. + ** Has to be the first entry, + ** because it's jumped to by the + ** script processor + */ + + struct head header; + + /* + ** Table data for Script + */ + + struct scr_tblsel select; + struct scr_tblmove smsg ; + struct scr_tblmove smsg2 ; + struct scr_tblmove cmd ; + struct scr_tblmove scmd ; + struct scr_tblmove sense ; + struct scr_tblmove data [MAX_SCATTER]; +}; + +/*========================================================== +** +** Declaration of structs: Command control block. +** +**========================================================== +** +** During execution of a ccb by the script processor, +** the DSA (data structure address) register points +** to this substructure of the ccb. +** This substructure contains the header with +** the script-processor-changable data and then +** data blocks for the indirect move commands. +** +**---------------------------------------------------------- +*/ + + +struct ccb { + /* + ** during reselection the ncr jumps to this point. + ** If a "SIMPLE_TAG" message was received, + ** then SFBR is set to the tag. + ** else SFBR is set to 0 + ** If looking for another tag, jump to the next ccb. + ** + ** JUMP IF (SFBR != #TAG#) + ** @(next ccb of this lun) + */ + + struct link jump_ccb; + + /* + ** After execution of this call, the return address + ** (in the TEMP register) points to the following + ** data structure block. + ** So copy it to the DSA register, and start + ** processing of this data structure. + ** + ** CALL + ** + */ + + struct link call_tmp; + + /* + ** This is the data structure which is + ** to be executed by the script processor. + */ + + struct dsb phys; + + /* + ** If a data transfer phase is terminated too early + ** (after reception of a message (i.e. DISCONNECT)), + ** we have to prepare a mini script to transfer + ** the rest of the data. + */ + + ncrcmd patch[8]; + + /* + ** The general SCSI driver provides a + ** pointer to a control block. + */ + + Scsi_Cmnd *cmd; + int data_len; + + /* + ** We prepare a message to be sent after selection, + ** and a second one to be sent after getcc selection. + ** Contents are IDENTIFY and SIMPLE_TAG. + ** While negotiating sync or wide transfer, + ** a SDTM or WDTM message is appended. + */ + + u_char scsi_smsg [8]; + u_char scsi_smsg2[8]; + + /* + ** Lock this ccb. + ** Flag is used while looking for a free ccb. + */ + + u_long magic; + + /* + ** Physical address of this instance of ccb + */ + + u_long p_ccb; + + /* + ** Completion time out for this job. + ** It's set to time of start + allowed number of seconds. + */ + + u_long tlimit; + + /* + ** All ccbs of one hostadapter are chained. + */ + + ccb_p link_ccb; + + /* + ** All ccbs of one target/lun are chained. + */ + + ccb_p next_ccb; + + /* + ** Sense command + */ + + u_char sensecmd[6]; + + /* + ** Tag for this transfer. + ** It's patched into jump_ccb. + ** If it's not zero, a SIMPLE_TAG + ** message is included in smsg. + */ + + u_char tag; +}; + +#define CCB_PHYS(cp,lbl) (cp->p_ccb + offsetof(struct ccb, lbl)) + +/*========================================================== +** +** Declaration of structs: NCR device descriptor +** +**========================================================== +*/ + +struct ncb { + /*----------------------------------------------- + ** Specific Linux fields + **----------------------------------------------- + */ + int unit; /* Unit number */ + int chip; /* Chip number */ + struct timer_list timer; /* Timer link header */ + int ncr_cache; /* Cache test variable */ + int release_stage; /* Synchronisation stage on release */ + Scsi_Cmnd *waiting_list; /* Waiting list header for commands */ + /* that we can't put into the squeue */ +#ifndef NCR_IOMAPPED + volatile struct ncr_reg* + reg_remapped; /* Virtual address of the memory */ + /* base of the ncr chip */ + int use_mmio; /* Indicate mmio is OK */ +#endif + /*----------------------------------------------- + ** Added field to support differences + ** between ncr chips. + **----------------------------------------------- + */ + u_short device_id; + u_char revision_id; +#define ChipDevice ((np)->device_id) +#define ChipVersion ((np)->revision_id & 0xf0) + + /*----------------------------------------------- + ** Scripts .. + **----------------------------------------------- + ** + ** During reselection the ncr jumps to this point. + ** The SFBR register is loaded with the encoded target id. + ** + ** Jump to the first target. + ** + ** JUMP + ** @(next tcb) + */ + struct link jump_tcb; + + /*----------------------------------------------- + ** Configuration .. + **----------------------------------------------- + ** + ** virtual and physical addresses + ** of the 53c810 chip. + */ + vm_offset_t vaddr; + vm_offset_t paddr; + + /* + ** pointer to the chip's registers. + */ + volatile + struct ncr_reg* reg; + + /* + ** A copy of the script, relocated for this ncb. + */ + struct script *script; + + /* + ** Physical address of this instance of ncb->script + */ + u_long p_script; + + /* + ** The SCSI address of the host adapter. + */ + u_char myaddr; + + /* + ** timing parameters + */ + u_char ns_async; + u_char ns_sync; + u_char rv_scntl3; + + /*----------------------------------------------- + ** Link to the generic SCSI driver + **----------------------------------------------- + */ + + /* struct scsi_link sc_link; */ + + /*----------------------------------------------- + ** Job control + **----------------------------------------------- + ** + ** Commands from user + */ + struct usrcmd user; + u_char order; + + /* + ** Target data + */ + struct tcb target[MAX_TARGET]; + + /* + ** Start queue. + */ + u_long squeue [MAX_START]; + u_short squeueput; + u_short actccbs; + + /* + ** Timeout handler + */ + u_long heartbeat; + u_short ticks; + u_short latetime; + u_long lasttime; + + /*----------------------------------------------- + ** Debug and profiling + **----------------------------------------------- + ** + ** register dump + */ + struct ncr_reg regdump; + u_long regtime; + + /* + ** Profiling data + */ + struct profile profile; + u_long disc_phys; + u_long disc_ref; + + /* + ** The global header. + ** Accessible to both the host and the + ** script-processor. + */ + struct head header; + + /* + ** The global control block. + ** It's used only during the configuration phase. + ** A target control block will be created + ** after the first successful transfer. + */ + struct ccb ccb; + + /* + ** message buffers. + ** Should be longword aligned, + ** because they're written with a + ** COPY script command. + */ + u_char msgout[8]; + u_char msgin [8]; + u_long lastmsg; + + /* + ** Buffer for STATUS_IN phase. + */ + u_char scratch; + + /* + ** controller chip dependent maximal transfer width. + */ + u_char maxwide; + + /* + ** option for M_IDENTIFY message: enables disconnecting + */ + u_char disc; + + /* + ** address of the ncr control registers in io space + */ + u_int port; + + /* + ** irq level + */ + u_short irq; +}; + +#define NCB_SCRIPT_PHYS(np,lbl) (np->p_script + offsetof (struct script, lbl)) + +/*========================================================== +** +** +** Script for NCR-Processor. +** +** Use ncr_script_fill() to create the variable parts. +** Use ncr_script_copy_and_bind() to make a copy and +** bind to physical addresses. +** +** +**========================================================== +** +** We have to know the offsets of all labels before +** we reach them (for forward jumps). +** Therefore we declare a struct here. +** If you make changes inside the script, +** DONT FORGET TO CHANGE THE LENGTHS HERE! +** +**---------------------------------------------------------- +*/ + +struct script { + ncrcmd start [ 7]; + ncrcmd start0 [ 2]; + ncrcmd start1 [ 3]; + ncrcmd startpos [ 1]; + ncrcmd tryloop [MAX_START*5+2]; + ncrcmd trysel [ 8]; + ncrcmd skip [ 8]; + ncrcmd skip2 [ 3]; + ncrcmd idle [ 2]; + ncrcmd select [ 22]; + ncrcmd prepare [ 4]; + ncrcmd loadpos [ 14]; + ncrcmd prepare2 [ 24]; + ncrcmd setmsg [ 5]; + ncrcmd clrack [ 2]; + ncrcmd dispatch [ 33]; + ncrcmd no_data [ 17]; + ncrcmd checkatn [ 10]; + ncrcmd command [ 15]; + ncrcmd status [ 27]; + ncrcmd msg_in [ 26]; + ncrcmd msg_bad [ 6]; + ncrcmd msg_parity [ 6]; + ncrcmd msg_reject [ 8]; + ncrcmd msg_ign_residue [ 32]; + ncrcmd msg_extended [ 18]; + ncrcmd msg_ext_2 [ 18]; + ncrcmd msg_wdtr [ 27]; + ncrcmd msg_ext_3 [ 18]; + ncrcmd msg_sdtr [ 27]; + ncrcmd complete [ 13]; + ncrcmd cleanup [ 12]; + ncrcmd cleanup0 [ 11]; + ncrcmd signal [ 10]; + ncrcmd save_dp [ 5]; + ncrcmd restore_dp [ 5]; + ncrcmd disconnect [ 12]; + ncrcmd disconnect0 [ 5]; + ncrcmd disconnect1 [ 23]; + ncrcmd msg_out [ 9]; + ncrcmd msg_out_done [ 7]; + ncrcmd msg_out_abort [ 10]; + ncrcmd getcc [ 4]; + ncrcmd getcc1 [ 5]; +#ifdef NCR_GETCC_WITHMSG + ncrcmd getcc2 [ 33]; +#else + ncrcmd getcc2 [ 14]; +#endif + ncrcmd getcc3 [ 10]; + ncrcmd badgetcc [ 6]; + ncrcmd reselect [ 12]; + ncrcmd reselect2 [ 6]; + ncrcmd resel_tmp [ 5]; + ncrcmd resel_lun [ 18]; + ncrcmd resel_tag [ 24]; + ncrcmd data_in [MAX_SCATTER * 4 + 7]; + ncrcmd data_out [MAX_SCATTER * 4 + 7]; + ncrcmd aborttag [ 4]; + ncrcmd abort [ 22]; + ncrcmd snooptest [ 9]; + ncrcmd snoopend [ 2]; +}; + +/*========================================================== +** +** +** Function headers. +** +** +**========================================================== +*/ + +static void ncr_alloc_ccb (ncb_p np, u_long t, u_long l); +static void ncr_complete (ncb_p np, ccb_p cp); +static void ncr_exception (ncb_p np); +static void ncr_free_ccb (ncb_p np, ccb_p cp); +static void ncr_getclock (ncb_p np); +static ccb_p ncr_get_ccb (ncb_p np, u_long t,u_long l); +static void ncr_init (ncb_p np, char * msg, u_long code); +static int ncr_intr (ncb_p np); +static void ncr_int_ma (ncb_p np); +static void ncr_int_sir (ncb_p np); +static void ncr_int_sto (ncb_p np); +static u_long ncr_lookup (char* id); +static void ncr_negotiate (struct ncb* np, struct tcb* tp); + +#ifdef SCSI_NCR_PROFILE +static int ncr_delta (u_long from, u_long to); +static void ncb_profile (ncb_p np, ccb_p cp); +#endif + +static void ncr_script_copy_and_bind + (struct script * script, ncb_p np); +static void ncr_script_fill (struct script * scr); +static int ncr_scatter (ccb_p cp, Scsi_Cmnd *cmd); +static void ncr_setmaxtags (ncb_p np, tcb_p tp, u_long usrtags); +static void ncr_setsync (ncb_p np, ccb_p cp, u_char sxfer); +static void ncr_settags (tcb_p tp, lcb_p lp); +static void ncr_setwide (ncb_p np, ccb_p cp, u_char wide); +static int ncr_show_msg (u_char * msg); +static int ncr_snooptest (ncb_p np); +static void ncr_timeout (ncb_p np); +static void ncr_wakeup (ncb_p np, u_long code); + +#ifdef SCSI_NCR_USER_COMMAND +static void ncr_usercmd (ncb_p np); +#endif + +static int ncr_attach (Scsi_Host_Template *tpnt, int unit, u_short device_id, + u_char revision_id, int chip, u_int base, u_int io_port, + int irq, int bus, u_char device_fn); + +static void insert_into_waiting_list(ncb_p np, Scsi_Cmnd *cmd); +static Scsi_Cmnd *remove_from_waiting_list(ncb_p np, Scsi_Cmnd *cmd); +static void process_waiting_list(ncb_p np, int sts); + +#define requeue_waiting_list(np) process_waiting_list((np), DID_OK) +#define abort_waiting_list(np) process_waiting_list((np), DID_ABORT) +#define reset_waiting_list(np) process_waiting_list((np), DID_RESET) + +/*========================================================== +** +** +** Global static data. +** +** +**========================================================== +*/ + +#if 0 +static char ident[] = + "\n$Id: ncr.c,v 1.67 1996/03/11 19:36:07 se Exp $\n"; +static u_long ncr_version = NCR_VERSION * 11 + + (u_long) sizeof (struct ncb) * 7 + + (u_long) sizeof (struct ccb) * 5 + + (u_long) sizeof (struct lcb) * 3 + + (u_long) sizeof (struct tcb) * 2; +#endif + +#ifdef SCSI_NCR_DEBUG +static int ncr_debug = SCSI_NCR_DEBUG_FLAGS; +#endif + +/*========================================================== +** +** +** Global static data: auto configure +** +** +**========================================================== +*/ + +static char *ncr_name (ncb_p np) +{ + static char name[10]; + sprintf(name, "ncr53c%d-%d", np->chip, np->unit); + return (name); +} + + +/*========================================================== +** +** +** Scripts for NCR-Processor. +** +** Use ncr_script_bind for binding to physical addresses. +** +** +**========================================================== +** +** NADDR generates a reference to a field of the controller data. +** PADDR generates a reference to another part of the script. +** RADDR generates a reference to a script processor register. +** FADDR generates a reference to a script processor register +** with offset. +** +**---------------------------------------------------------- +*/ + +#define RELOC_SOFTC 0x40000000 +#define RELOC_LABEL 0x50000000 +#define RELOC_REGISTER 0x60000000 +#define RELOC_KVAR 0x70000000 +#define RELOC_MASK 0xf0000000 + +#define NADDR(label) (RELOC_SOFTC | offsetof(struct ncb, label)) +#define PADDR(label) (RELOC_LABEL | offsetof(struct script, label)) +#define RADDR(label) (RELOC_REGISTER | REG(label)) +#define FADDR(label,ofs)(RELOC_REGISTER | ((REG(label))+(ofs))) +#define KVAR(which) (RELOC_KVAR | (which)) + +#define SCRIPT_KVAR_JIFFIES (0) + +#define SCRIPT_KVAR_FIRST SCRIPT_KVAR_JIFFIES +#define SCRIPT_KVAR_LAST SCRIPT_KVAR_JIFFIES + +/* + * Kernel variables referenced in the scripts. + * THESE MUST ALL BE ALIGNED TO A 4-BYTE BOUNDARY. + */ +static void *script_kvars[] = + { (void *)&jiffies }; + +static struct script script0 = { +/*--------------------------< START >-----------------------*/ { + /* + ** Claim to be still alive ... + */ + SCR_COPY (sizeof (((struct ncb *)0)->heartbeat)), + KVAR(SCRIPT_KVAR_JIFFIES), + NADDR (heartbeat), + + /* + ** Make data structure address invalid. + ** clear SIGP. + */ + SCR_LOAD_REG (dsa, 0xff), + 0, + SCR_FROM_REG (ctest2), + 0, +}/*-------------------------< START0 >----------------------*/,{ + /* + ** Hook for interrupted GetConditionCode. + ** Will be patched to ... IFTRUE by + ** the interrupt handler. + */ + SCR_INT ^ IFFALSE (0), + SIR_SENSE_RESTART, + +}/*-------------------------< START1 >----------------------*/,{ + /* + ** Hook for stalled start queue. + ** Will be patched to IFTRUE by the interrupt handler. + */ + SCR_INT ^ IFFALSE (0), + SIR_STALL_RESTART, + /* + ** Then jump to a certain point in tryloop. + ** Due to the lack of indirect addressing the code + ** is self modifying here. + */ + SCR_JUMP, +}/*-------------------------< STARTPOS >--------------------*/,{ + PADDR(tryloop), +}/*-------------------------< TRYLOOP >---------------------*/,{ +/* +** Load an entry of the start queue into dsa +** and try to start it by jumping to TRYSEL. +** +** Because the size depends on the +** #define MAX_START parameter, it is filled +** in at runtime. +** +**----------------------------------------------------------- +** +** ##===========< I=0; i=========== +** || SCR_COPY (4), +** || NADDR (squeue[i]), +** || RADDR (dsa), +** || SCR_CALL, +** || PADDR (trysel), +** ##========================================== +** +** SCR_JUMP, +** PADDR(tryloop), +** +**----------------------------------------------------------- +*/ +0 + +}/*-------------------------< TRYSEL >----------------------*/,{ + /* + ** Now: + ** DSA: Address of a Data Structure + ** or Address of the IDLE-Label. + ** + ** TEMP: Address of a script, which tries to + ** start the NEXT entry. + ** + ** Save the TEMP register into the SCRATCHA register. + ** Then copy the DSA to TEMP and RETURN. + ** This is kind of an indirect jump. + ** (The script processor has NO stack, so the + ** CALL is actually a jump and link, and the + ** RETURN is an indirect jump.) + ** + ** If the slot was empty, DSA contains the address + ** of the IDLE part of this script. The processor + ** jumps to IDLE and waits for a reselect. + ** It will wake up and try the same slot again + ** after the SIGP bit becomes set by the host. + ** + ** If the slot was not empty, DSA contains + ** the address of the phys-part of a ccb. + ** The processor jumps to this address. + ** phys starts with head, + ** head starts with launch, + ** so actually the processor jumps to + ** the lauch part. + ** If the entry is scheduled for execution, + ** then launch contains a jump to SELECT. + ** If it's not scheduled, it contains a jump to IDLE. + */ + SCR_COPY (4), + RADDR (temp), + RADDR (scratcha), + SCR_COPY (4), + RADDR (dsa), + RADDR (temp), + SCR_RETURN, + 0 + +}/*-------------------------< SKIP >------------------------*/,{ + /* + ** This entry has been canceled. + ** Next time use the next slot. + */ + SCR_COPY (4), + RADDR (scratcha), + PADDR (startpos), + /* + ** patch the launch field. + ** should look like an idle process. + */ + SCR_COPY (4), + RADDR (dsa), + PADDR (skip2), + SCR_COPY (8), + PADDR (idle), +}/*-------------------------< SKIP2 >-----------------------*/,{ + 0, + SCR_JUMP, + PADDR(start), +}/*-------------------------< IDLE >------------------------*/,{ + /* + ** Nothing to do? + ** Wait for reselect. + */ + SCR_JUMP, + PADDR(reselect), + +}/*-------------------------< SELECT >----------------------*/,{ + /* + ** DSA contains the address of a scheduled + ** data structure. + ** + ** SCRATCHA contains the address of the script, + ** which starts the next entry. + ** + ** Set Initiator mode. + ** + ** (Target mode is left as an exercise for the reader) + */ + + SCR_CLR (SCR_TRG), + 0, + SCR_LOAD_REG (HS_REG, 0xff), + 0, + + /* + ** And try to select this target. + */ + SCR_SEL_TBL_ATN ^ offsetof (struct dsb, select), + PADDR (reselect), + + /* + ** Now there are 4 possibilities: + ** + ** (1) The ncr looses arbitration. + ** This is ok, because it will try again, + ** when the bus becomes idle. + ** (But beware of the timeout function!) + ** + ** (2) The ncr is reselected. + ** Then the script processor takes the jump + ** to the RESELECT label. + ** + ** (3) The ncr completes the selection. + ** Then it will execute the next statement. + ** + ** (4) There is a selection timeout. + ** Then the ncr should interrupt the host and stop. + ** Unfortunately, it seems to continue execution + ** of the script. But it will fail with an + ** IID-interrupt on the next WHEN. + */ + + SCR_JUMPR ^ IFTRUE (WHEN (SCR_MSG_IN)), + 0, + + /* + ** Save target id to ctest0 register + */ + + SCR_FROM_REG (sdid), + 0, + SCR_TO_REG (ctest0), + 0, + /* + ** Send the IDENTIFY and SIMPLE_TAG messages + ** (and the M_X_SYNC_REQ message) + */ + SCR_MOVE_TBL ^ SCR_MSG_OUT, + offsetof (struct dsb, smsg), +#ifdef undef /* XXX better fail than try to deal with this ... */ + SCR_JUMPR ^ IFTRUE (WHEN (SCR_MSG_OUT)), + -16, +#endif + SCR_CLR (SCR_ATN), + 0, + SCR_COPY (1), + RADDR (sfbr), + NADDR (lastmsg), + /* + ** Selection complete. + ** Next time use the next slot. + */ + SCR_COPY (4), + RADDR (scratcha), + PADDR (startpos), +}/*-------------------------< PREPARE >----------------------*/,{ + /* + ** The ncr doesn't have an indirect load + ** or store command. So we have to + ** copy part of the control block to a + ** fixed place, where we can access it. + ** + ** We patch the address part of a + ** COPY command with the DSA-register. + */ + SCR_COPY (4), + RADDR (dsa), + PADDR (loadpos), + /* + ** then we do the actual copy. + */ + SCR_COPY (sizeof (struct head)), + /* + ** continued after the next label ... + */ + +}/*-------------------------< LOADPOS >---------------------*/,{ + 0, + NADDR (header), + /* + ** Mark this ccb as not scheduled. + */ + SCR_COPY (8), + PADDR (idle), + NADDR (header.launch), + /* + ** Set a time stamp for this selection + */ + SCR_COPY (sizeof (u_long)), + KVAR(SCRIPT_KVAR_JIFFIES), + NADDR (header.stamp.select), + /* + ** load the savep (saved pointer) into + ** the TEMP register (actual pointer) + */ + SCR_COPY (4), + NADDR (header.savep), + RADDR (temp), + /* + ** Initialize the status registers + */ + SCR_COPY (4), + NADDR (header.status), + RADDR (scr0), + +}/*-------------------------< PREPARE2 >---------------------*/,{ + /* + ** Load the synchronous mode register + */ + SCR_COPY (1), + NADDR (sync_st), + RADDR (sxfer), + /* + ** Load the wide mode and timing register + */ + SCR_COPY (1), + NADDR (wide_st), + RADDR (scntl3), + /* + ** Initialize the msgout buffer with a NOOP message. + */ + SCR_LOAD_REG (scratcha, M_NOOP), + 0, + SCR_COPY (1), + RADDR (scratcha), + NADDR (msgout), + SCR_COPY (1), + RADDR (scratcha), + NADDR (msgin), + /* + ** Message in phase ? + */ + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), + PADDR (dispatch), + /* + ** Extended or reject message ? + */ + SCR_FROM_REG (sbdl), + 0, + SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)), + PADDR (msg_in), + SCR_JUMP ^ IFTRUE (DATA (M_REJECT)), + PADDR (msg_reject), + /* + ** normal processing + */ + SCR_JUMP, + PADDR (dispatch), +}/*-------------------------< SETMSG >----------------------*/,{ + SCR_COPY (1), + RADDR (scratcha), + NADDR (msgout), + SCR_SET (SCR_ATN), + 0, +}/*-------------------------< CLRACK >----------------------*/,{ + /* + ** Terminate possible pending message phase. + */ + SCR_CLR (SCR_ACK), + 0, + +}/*-----------------------< DISPATCH >----------------------*/,{ + SCR_FROM_REG (HS_REG), + 0, + SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)), + SIR_NEGO_FAILED, + /* + ** remove bogus output signals + */ + SCR_REG_REG (socl, SCR_AND, CACK|CATN), + 0, + SCR_RETURN ^ IFTRUE (WHEN (SCR_DATA_OUT)), + 0, + SCR_RETURN ^ IFTRUE (IF (SCR_DATA_IN)), + 0, + SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT)), + PADDR (msg_out), + SCR_JUMP ^ IFTRUE (IF (SCR_MSG_IN)), + PADDR (msg_in), + SCR_JUMP ^ IFTRUE (IF (SCR_COMMAND)), + PADDR (command), + SCR_JUMP ^ IFTRUE (IF (SCR_STATUS)), + PADDR (status), + /* + ** Discard one illegal phase byte, if required. + */ + SCR_LOAD_REG (scratcha, XE_BAD_PHASE), + 0, + SCR_COPY (1), + RADDR (scratcha), + NADDR (xerr_st), + SCR_JUMPR ^ IFFALSE (IF (SCR_ILG_OUT)), + 8, + SCR_MOVE_ABS (1) ^ SCR_ILG_OUT, + NADDR (scratch), + SCR_JUMPR ^ IFFALSE (IF (SCR_ILG_IN)), + 8, + SCR_MOVE_ABS (1) ^ SCR_ILG_IN, + NADDR (scratch), + SCR_JUMP, + PADDR (dispatch), + +}/*-------------------------< NO_DATA >--------------------*/,{ + /* + ** The target wants to tranfer too much data + ** or in the wrong direction. + ** Remember that in extended error. + */ + SCR_LOAD_REG (scratcha, XE_EXTRA_DATA), + 0, + SCR_COPY (1), + RADDR (scratcha), + NADDR (xerr_st), + /* + ** Discard one data byte, if required. + */ + SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_OUT)), + 8, + SCR_MOVE_ABS (1) ^ SCR_DATA_OUT, + NADDR (scratch), + SCR_JUMPR ^ IFFALSE (IF (SCR_DATA_IN)), + 8, + SCR_MOVE_ABS (1) ^ SCR_DATA_IN, + NADDR (scratch), + /* + ** .. and repeat as required. + */ + SCR_CALL, + PADDR (dispatch), + SCR_JUMP, + PADDR (no_data), +}/*-------------------------< CHECKATN >--------------------*/,{ + /* + ** If AAP (bit 1 of scntl0 register) is set + ** and a parity error is detected, + ** the script processor asserts ATN. + ** + ** The target should switch to a MSG_OUT phase + ** to get the message. + */ + SCR_FROM_REG (socl), + 0, + SCR_JUMP ^ IFFALSE (MASK (CATN, CATN)), + PADDR (dispatch), + /* + ** count it + */ + SCR_REG_REG (PS_REG, SCR_ADD, 1), + 0, + /* + ** Prepare a M_ID_ERROR message + ** (initiator detected error). + ** The target should retry the transfer. + */ + SCR_LOAD_REG (scratcha, M_ID_ERROR), + 0, + SCR_JUMP, + PADDR (setmsg), + +}/*-------------------------< COMMAND >--------------------*/,{ + /* + ** If this is not a GETCC transfer ... + */ + SCR_FROM_REG (SS_REG), + 0, +/*<<<*/ SCR_JUMPR ^ IFTRUE (DATA (S_CHECK_COND)), + 28, + /* + ** ... set a timestamp ... + */ + SCR_COPY (sizeof (u_long)), + KVAR(SCRIPT_KVAR_JIFFIES), + NADDR (header.stamp.command), + /* + ** ... and send the command + */ + SCR_MOVE_TBL ^ SCR_COMMAND, + offsetof (struct dsb, cmd), + SCR_JUMP, + PADDR (dispatch), + /* + ** Send the GETCC command + */ +/*>>>*/ SCR_MOVE_TBL ^ SCR_COMMAND, + offsetof (struct dsb, scmd), + SCR_JUMP, + PADDR (dispatch), + +}/*-------------------------< STATUS >--------------------*/,{ + /* + ** set the timestamp. + */ + SCR_COPY (sizeof (u_long)), + KVAR(SCRIPT_KVAR_JIFFIES), + NADDR (header.stamp.status), + /* + ** If this is a GETCC transfer, + */ + SCR_FROM_REG (SS_REG), + 0, +/*<<<*/ SCR_JUMPR ^ IFFALSE (DATA (S_CHECK_COND)), + 40, + /* + ** get the status + */ + SCR_MOVE_ABS (1) ^ SCR_STATUS, + NADDR (scratch), + /* + ** Save status to scsi_status. + ** Mark as complete. + ** And wait for disconnect. + */ + SCR_TO_REG (SS_REG), + 0, + SCR_REG_REG (SS_REG, SCR_OR, S_SENSE), + 0, + SCR_LOAD_REG (HS_REG, HS_COMPLETE), + 0, + SCR_JUMP, + PADDR (checkatn), + /* + ** If it was no GETCC transfer, + ** save the status to scsi_status. + */ +/*>>>*/ SCR_MOVE_ABS (1) ^ SCR_STATUS, + NADDR (scratch), + SCR_TO_REG (SS_REG), + 0, + /* + ** if it was no check condition ... + */ + SCR_JUMP ^ IFTRUE (DATA (S_CHECK_COND)), + PADDR (checkatn), + /* + ** ... mark as complete. + */ + SCR_LOAD_REG (HS_REG, HS_COMPLETE), + 0, + SCR_JUMP, + PADDR (checkatn), + +}/*-------------------------< MSG_IN >--------------------*/,{ + /* + ** Get the first byte of the message + ** and save it to SCRATCHA. + ** + ** The script processor doesn't negate the + ** ACK signal after this transfer. + */ + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin[0]), + /* + ** Check for message parity error. + */ + SCR_TO_REG (scratcha), + 0, + SCR_FROM_REG (socl), + 0, + SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)), + PADDR (msg_parity), + SCR_FROM_REG (scratcha), + 0, + /* + ** Parity was ok, handle this message. + */ + SCR_JUMP ^ IFTRUE (DATA (M_COMPLETE)), + PADDR (complete), + SCR_JUMP ^ IFTRUE (DATA (M_SAVE_DP)), + PADDR (save_dp), + SCR_JUMP ^ IFTRUE (DATA (M_RESTORE_DP)), + PADDR (restore_dp), + SCR_JUMP ^ IFTRUE (DATA (M_DISCONNECT)), + PADDR (disconnect), + SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)), + PADDR (msg_extended), + SCR_JUMP ^ IFTRUE (DATA (M_NOOP)), + PADDR (clrack), + SCR_JUMP ^ IFTRUE (DATA (M_REJECT)), + PADDR (msg_reject), + SCR_JUMP ^ IFTRUE (DATA (M_IGN_RESIDUE)), + PADDR (msg_ign_residue), + /* + ** Rest of the messages left as + ** an exercise ... + ** + ** Unimplemented messages: + ** fall through to MSG_BAD. + */ +}/*-------------------------< MSG_BAD >------------------*/,{ + /* + ** unimplemented message - reject it. + */ + SCR_INT, + SIR_REJECT_SENT, + SCR_LOAD_REG (scratcha, M_REJECT), + 0, + SCR_JUMP, + PADDR (setmsg), + +}/*-------------------------< MSG_PARITY >---------------*/,{ + /* + ** count it + */ + SCR_REG_REG (PS_REG, SCR_ADD, 0x01), + 0, + /* + ** send a "message parity error" message. + */ + SCR_LOAD_REG (scratcha, M_PARITY), + 0, + SCR_JUMP, + PADDR (setmsg), +}/*-------------------------< MSG_REJECT >---------------*/,{ + /* + ** If a negotiation was in progress, + ** negotiation failed. + */ + SCR_FROM_REG (HS_REG), + 0, + SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)), + SIR_NEGO_FAILED, + /* + ** else make host log this message + */ + SCR_INT ^ IFFALSE (DATA (HS_NEGOTIATE)), + SIR_REJECT_RECEIVED, + SCR_JUMP, + PADDR (clrack), + +}/*-------------------------< MSG_IGN_RESIDUE >----------*/,{ + /* + ** Terminate cycle + */ + SCR_CLR (SCR_ACK), + 0, + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), + PADDR (dispatch), + /* + ** get residue size. + */ + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin[1]), + /* + ** Check for message parity error. + */ + SCR_TO_REG (scratcha), + 0, + SCR_FROM_REG (socl), + 0, + SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)), + PADDR (msg_parity), + SCR_FROM_REG (scratcha), + 0, + /* + ** Size is 0 .. ignore message. + */ + SCR_JUMP ^ IFTRUE (DATA (0)), + PADDR (clrack), + /* + ** Size is not 1 .. have to interrupt. + */ +/*<<<*/ SCR_JUMPR ^ IFFALSE (DATA (1)), + 40, + /* + ** Check for residue byte in swide register + */ + SCR_FROM_REG (scntl2), + 0, +/*<<<*/ SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)), + 16, + /* + ** There IS data in the swide register. + ** Discard it. + */ + SCR_REG_REG (scntl2, SCR_OR, WSR), + 0, + SCR_JUMP, + PADDR (clrack), + /* + ** Load again the size to the sfbr register. + */ +/*>>>*/ SCR_FROM_REG (scratcha), + 0, +/*>>>*/ SCR_INT, + SIR_IGN_RESIDUE, + SCR_JUMP, + PADDR (clrack), + +}/*-------------------------< MSG_EXTENDED >-------------*/,{ + /* + ** Terminate cycle + */ + SCR_CLR (SCR_ACK), + 0, + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), + PADDR (dispatch), + /* + ** get length. + */ + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin[1]), + /* + ** Check for message parity error. + */ + SCR_TO_REG (scratcha), + 0, + SCR_FROM_REG (socl), + 0, + SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)), + PADDR (msg_parity), + SCR_FROM_REG (scratcha), + 0, + /* + */ + SCR_JUMP ^ IFTRUE (DATA (3)), + PADDR (msg_ext_3), + SCR_JUMP ^ IFFALSE (DATA (2)), + PADDR (msg_bad), +}/*-------------------------< MSG_EXT_2 >----------------*/,{ + SCR_CLR (SCR_ACK), + 0, + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), + PADDR (dispatch), + /* + ** get extended message code. + */ + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin[2]), + /* + ** Check for message parity error. + */ + SCR_TO_REG (scratcha), + 0, + SCR_FROM_REG (socl), + 0, + SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)), + PADDR (msg_parity), + SCR_FROM_REG (scratcha), + 0, + SCR_JUMP ^ IFTRUE (DATA (M_X_WIDE_REQ)), + PADDR (msg_wdtr), + /* + ** unknown extended message + */ + SCR_JUMP, + PADDR (msg_bad) +}/*-------------------------< MSG_WDTR >-----------------*/,{ + SCR_CLR (SCR_ACK), + 0, + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), + PADDR (dispatch), + /* + ** get data bus width + */ + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin[3]), + SCR_FROM_REG (socl), + 0, + SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)), + PADDR (msg_parity), + /* + ** let the host do the real work. + */ + SCR_INT, + SIR_NEGO_WIDE, + /* + ** let the target fetch our answer. + */ + SCR_SET (SCR_ATN), + 0, + SCR_CLR (SCR_ACK), + 0, + + SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)), + SIR_NEGO_PROTO, + /* + ** Send the M_X_WIDE_REQ + */ + SCR_MOVE_ABS (4) ^ SCR_MSG_OUT, + NADDR (msgout), + SCR_CLR (SCR_ATN), + 0, + SCR_COPY (1), + RADDR (sfbr), + NADDR (lastmsg), + SCR_JUMP, + PADDR (msg_out_done), + +}/*-------------------------< MSG_EXT_3 >----------------*/,{ + SCR_CLR (SCR_ACK), + 0, + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), + PADDR (dispatch), + /* + ** get extended message code. + */ + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin[2]), + /* + ** Check for message parity error. + */ + SCR_TO_REG (scratcha), + 0, + SCR_FROM_REG (socl), + 0, + SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)), + PADDR (msg_parity), + SCR_FROM_REG (scratcha), + 0, + SCR_JUMP ^ IFTRUE (DATA (M_X_SYNC_REQ)), + PADDR (msg_sdtr), + /* + ** unknown extended message + */ + SCR_JUMP, + PADDR (msg_bad) + +}/*-------------------------< MSG_SDTR >-----------------*/,{ + SCR_CLR (SCR_ACK), + 0, + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), + PADDR (dispatch), + /* + ** get period and offset + */ + SCR_MOVE_ABS (2) ^ SCR_MSG_IN, + NADDR (msgin[3]), + SCR_FROM_REG (socl), + 0, + SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)), + PADDR (msg_parity), + /* + ** let the host do the real work. + */ + SCR_INT, + SIR_NEGO_SYNC, + /* + ** let the target fetch our answer. + */ + SCR_SET (SCR_ATN), + 0, + SCR_CLR (SCR_ACK), + 0, + + SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)), + SIR_NEGO_PROTO, + /* + ** Send the M_X_SYNC_REQ + */ + SCR_MOVE_ABS (5) ^ SCR_MSG_OUT, + NADDR (msgout), + SCR_CLR (SCR_ATN), + 0, + SCR_COPY (1), + RADDR (sfbr), + NADDR (lastmsg), + SCR_JUMP, + PADDR (msg_out_done), + +}/*-------------------------< COMPLETE >-----------------*/,{ + /* + ** Complete message. + ** + ** If it's not the get condition code, + ** copy TEMP register to LASTP in header. + */ + SCR_FROM_REG (SS_REG), + 0, +/*<<<*/ SCR_JUMPR ^ IFTRUE (MASK (S_SENSE, S_SENSE)), + 12, + SCR_COPY (4), + RADDR (temp), + NADDR (header.lastp), +/*>>>*/ /* + ** When we terminate the cycle by clearing ACK, + ** the target may disconnect immediately. + ** + ** We don't want to be told of an + ** "unexpected disconnect", + ** so we disable this feature. + */ + SCR_REG_REG (scntl2, SCR_AND, 0x7f), + 0, + /* + ** Terminate cycle ... + */ + SCR_CLR (SCR_ACK|SCR_ATN), + 0, + /* + ** ... and wait for the disconnect. + */ + SCR_WAIT_DISC, + 0, +}/*-------------------------< CLEANUP >-------------------*/,{ + /* + ** dsa: Pointer to ccb + ** or xxxxxxFF (no ccb) + ** + ** HS_REG: Host-Status (<>0!) + */ + SCR_FROM_REG (dsa), + 0, + SCR_JUMP ^ IFTRUE (DATA (0xff)), + PADDR (signal), + /* + ** dsa is valid. + ** save the status registers + */ + SCR_COPY (4), + RADDR (scr0), + NADDR (header.status), + /* + ** and copy back the header to the ccb. + */ + SCR_COPY (4), + RADDR (dsa), + PADDR (cleanup0), + SCR_COPY (sizeof (struct head)), + NADDR (header), +}/*-------------------------< CLEANUP0 >--------------------*/,{ + 0, + + /* + ** If command resulted in "check condition" + ** status and is not yet completed, + ** try to get the condition code. + */ + SCR_FROM_REG (HS_REG), + 0, +/*<<<*/ SCR_JUMPR ^ IFFALSE (MASK (0, HS_DONEMASK)), + 16, + SCR_FROM_REG (SS_REG), + 0, + SCR_JUMP ^ IFTRUE (DATA (S_CHECK_COND)), + PADDR(getcc2), + /* + ** And make the DSA register invalid. + */ +/*>>>*/ SCR_LOAD_REG (dsa, 0xff), /* invalid */ + 0, +}/*-------------------------< SIGNAL >----------------------*/,{ + /* + ** if status = queue full, + ** reinsert in startqueue and stall queue. + */ + SCR_FROM_REG (SS_REG), + 0, + SCR_INT ^ IFTRUE (DATA (S_QUEUE_FULL)), + SIR_STALL_QUEUE, + /* + ** if job completed ... + */ + SCR_FROM_REG (HS_REG), + 0, + /* + ** ... signal completion to the host + */ + SCR_INT_FLY ^ IFFALSE (MASK (0, HS_DONEMASK)), + 0, + /* + ** Auf zu neuen Schandtaten! + */ + SCR_JUMP, + PADDR(start), + +}/*-------------------------< SAVE_DP >------------------*/,{ + /* + ** SAVE_DP message: + ** Copy TEMP register to SAVEP in header. + */ + SCR_COPY (4), + RADDR (temp), + NADDR (header.savep), + SCR_JUMP, + PADDR (clrack), +}/*-------------------------< RESTORE_DP >---------------*/,{ + /* + ** RESTORE_DP message: + ** Copy SAVEP in header to TEMP register. + */ + SCR_COPY (4), + NADDR (header.savep), + RADDR (temp), + SCR_JUMP, + PADDR (clrack), + +}/*-------------------------< DISCONNECT >---------------*/,{ + /* + ** If QUIRK_AUTOSAVE is set, + ** do an "save pointer" operation. + */ + SCR_FROM_REG (QU_REG), + 0, +/*<<<*/ SCR_JUMPR ^ IFFALSE (MASK (QUIRK_AUTOSAVE, QUIRK_AUTOSAVE)), + 12, + /* + ** like SAVE_DP message: + ** Copy TEMP register to SAVEP in header. + */ + SCR_COPY (4), + RADDR (temp), + NADDR (header.savep), +/*>>>*/ /* + ** Check if temp==savep or temp==goalp: + ** if not, log a missing save pointer message. + ** In fact, it's a comparison mod 256. + ** + ** Hmmm, I hadn't thought that I would be urged to + ** write this kind of ugly self modifying code. + ** + ** It's unbelievable, but the ncr53c8xx isn't able + ** to subtract one register from another. + */ + SCR_FROM_REG (temp), + 0, + /* + ** You are not expected to understand this .. + ** + ** CAUTION: only little endian architectures supported! XXX + */ + SCR_COPY (1), + NADDR (header.savep), + PADDR (disconnect0), +}/*-------------------------< DISCONNECT0 >--------------*/,{ +/*<<<*/ SCR_JUMPR ^ IFTRUE (DATA (1)), + 20, + /* + ** neither this + */ + SCR_COPY (1), + NADDR (header.goalp), + PADDR (disconnect1), +}/*-------------------------< DISCONNECT1 >--------------*/,{ + SCR_INT ^ IFFALSE (DATA (1)), + SIR_MISSING_SAVE, +/*>>>*/ + + /* + ** DISCONNECTing ... + ** + ** disable the "unexpected disconnect" feature, + ** and remove the ACK signal. + */ + SCR_REG_REG (scntl2, SCR_AND, 0x7f), + 0, + SCR_CLR (SCR_ACK|SCR_ATN), + 0, + /* + ** Wait for the disconnect. + */ + SCR_WAIT_DISC, + 0, + /* + ** Profiling: + ** Set a time stamp, + ** and count the disconnects. + */ + SCR_COPY (sizeof (u_long)), + KVAR(SCRIPT_KVAR_JIFFIES), + NADDR (header.stamp.disconnect), + SCR_COPY (4), + NADDR (disc_phys), + RADDR (temp), + SCR_REG_REG (temp, SCR_ADD, 0x01), + 0, + SCR_COPY (4), + RADDR (temp), + NADDR (disc_phys), + /* + ** Status is: DISCONNECTED. + */ + SCR_LOAD_REG (HS_REG, HS_DISCONNECT), + 0, + SCR_JUMP, + PADDR (cleanup), + +}/*-------------------------< MSG_OUT >-------------------*/,{ + /* + ** The target requests a message. + */ + SCR_MOVE_ABS (1) ^ SCR_MSG_OUT, + NADDR (msgout), + SCR_COPY (1), + RADDR (sfbr), + NADDR (lastmsg), + /* + ** If it was no ABORT message ... + */ + SCR_JUMP ^ IFTRUE (DATA (M_ABORT)), + PADDR (msg_out_abort), + /* + ** ... wait for the next phase + ** if it's a message out, send it again, ... + */ + SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)), + PADDR (msg_out), +}/*-------------------------< MSG_OUT_DONE >--------------*/,{ + /* + ** ... else clear the message ... + */ + SCR_LOAD_REG (scratcha, M_NOOP), + 0, + SCR_COPY (4), + RADDR (scratcha), + NADDR (msgout), + /* + ** ... and process the next phase + */ + SCR_JUMP, + PADDR (dispatch), +}/*-------------------------< MSG_OUT_ABORT >-------------*/,{ + /* + ** After ABORT message, + ** + ** expect an immediate disconnect, ... + */ + SCR_REG_REG (scntl2, SCR_AND, 0x7f), + 0, + SCR_CLR (SCR_ACK|SCR_ATN), + 0, + SCR_WAIT_DISC, + 0, + /* + ** ... and set the status to "ABORTED" + */ + SCR_LOAD_REG (HS_REG, HS_ABORTED), + 0, + SCR_JUMP, + PADDR (cleanup), + +}/*-------------------------< GETCC >-----------------------*/,{ + /* + ** The ncr doesn't have an indirect load + ** or store command. So we have to + ** copy part of the control block to a + ** fixed place, where we can modify it. + ** + ** We patch the address part of a COPY command + ** with the address of the dsa register ... + */ + SCR_COPY (4), + RADDR (dsa), + PADDR (getcc1), + /* + ** ... then we do the actual copy. + */ + SCR_COPY (sizeof (struct head)), +}/*-------------------------< GETCC1 >----------------------*/,{ + 0, + NADDR (header), + /* + ** Initialize the status registers + */ + SCR_COPY (4), + NADDR (header.status), + RADDR (scr0), +}/*-------------------------< GETCC2 >----------------------*/,{ + /* + ** Get the condition code from a target. + ** + ** DSA points to a data structure. + ** Set TEMP to the script location + ** that receives the condition code. + ** + ** Because there is no script command + ** to load a longword into a register, + ** we use a CALL command. + */ +/*<<<*/ SCR_CALLR, + 24, + /* + ** Get the condition code. + */ + SCR_MOVE_TBL ^ SCR_DATA_IN, + offsetof (struct dsb, sense), + /* + ** No data phase may follow! + */ + SCR_CALL, + PADDR (checkatn), + SCR_JUMP, + PADDR (no_data), +/*>>>*/ + + /* + ** The CALL jumps to this point. + ** Prepare for a RESTORE_POINTER message. + ** Save the TEMP register into the saved pointer. + */ + SCR_COPY (4), + RADDR (temp), + NADDR (header.savep), + /* + ** Load scratcha, because in case of a selection timeout, + ** the host will expect a new value for startpos in + ** the scratcha register. + */ + SCR_COPY (4), + PADDR (startpos), + RADDR (scratcha), +#ifdef NCR_GETCC_WITHMSG + /* + ** If QUIRK_NOMSG is set, select without ATN. + ** and don't send a message. + */ + SCR_FROM_REG (QU_REG), + 0, + SCR_JUMP ^ IFTRUE (MASK (QUIRK_NOMSG, QUIRK_NOMSG)), + PADDR(getcc3), + /* + ** Then try to connect to the target. + ** If we are reselected, special treatment + ** of the current job is required before + ** accepting the reselection. + */ + SCR_SEL_TBL_ATN ^ offsetof (struct dsb, select), + PADDR(badgetcc), + /* + ** save target id. + */ + SCR_FROM_REG (sdid), + 0, + SCR_TO_REG (ctest0), + 0, + /* + ** Send the IDENTIFY message. + ** In case of short transfer, remove ATN. + */ + SCR_MOVE_TBL ^ SCR_MSG_OUT, + offsetof (struct dsb, smsg2), + SCR_CLR (SCR_ATN), + 0, + /* + ** save the first byte of the message. + */ + SCR_COPY (1), + RADDR (sfbr), + NADDR (lastmsg), + SCR_JUMP, + PADDR (prepare2), + +#endif +}/*-------------------------< GETCC3 >----------------------*/,{ + /* + ** Try to connect to the target. + ** If we are reselected, special treatment + ** of the current job is required before + ** accepting the reselection. + ** + ** Silly target won't accept a message. + ** Select without ATN. + */ + SCR_SEL_TBL ^ offsetof (struct dsb, select), + PADDR(badgetcc), + /* + ** save target id. + */ + SCR_FROM_REG (sdid), + 0, + SCR_TO_REG (ctest0), + 0, + /* + ** Force error if selection timeout + */ + SCR_JUMPR ^ IFTRUE (WHEN (SCR_MSG_IN)), + 0, + /* + ** don't negotiate. + */ + SCR_JUMP, + PADDR (prepare2), + +}/*------------------------< BADGETCC >---------------------*/,{ + /* + ** If SIGP was set, clear it and try again. + */ + SCR_FROM_REG (ctest2), + 0, + SCR_JUMP ^ IFTRUE (MASK (CSIGP,CSIGP)), + PADDR (getcc2), + SCR_INT, + SIR_SENSE_FAILED, +}/*-------------------------< RESELECT >--------------------*/,{ + /* + ** make the DSA invalid. + */ + SCR_LOAD_REG (dsa, 0xff), + 0, + SCR_CLR (SCR_TRG), + 0, + /* + ** Sleep waiting for a reselection. + ** If SIGP is set, special treatment. + ** + ** Zu allem bereit .. + */ + SCR_WAIT_RESEL, + PADDR(reselect2), + /* + ** ... zu nichts zu gebrauchen ? + ** + ** load the target id into the SFBR + ** and jump to the control block. + ** + ** Look at the declarations of + ** - struct ncb + ** - struct tcb + ** - struct lcb + ** - struct ccb + ** to understand what's going on. + */ + SCR_REG_SFBR (ssid, SCR_AND, 0x87), + 0, + SCR_TO_REG (ctest0), + 0, + SCR_JUMP, + NADDR (jump_tcb), +}/*-------------------------< RESELECT2 >-------------------*/,{ + /* + ** If it's not connected :( + ** -> interrupted by SIGP bit. + ** Jump to start. + */ + SCR_FROM_REG (ctest2), + 0, + SCR_JUMP ^ IFTRUE (MASK (CSIGP,CSIGP)), + PADDR (start), + SCR_JUMP, + PADDR (reselect), + +}/*-------------------------< RESEL_TMP >-------------------*/,{ + /* + ** The return address in TEMP + ** is in fact the data structure address, + ** so copy it to the DSA register. + */ + SCR_COPY (4), + RADDR (temp), + RADDR (dsa), + SCR_JUMP, + PADDR (prepare), + +}/*-------------------------< RESEL_LUN >-------------------*/,{ + /* + ** come back to this point + ** to get an IDENTIFY message + ** Wait for a msg_in phase. + */ +/*<<<*/ SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)), + 48, + /* + ** message phase + ** It's not a sony, it's a trick: + ** read the data without acknowledging it. + */ + SCR_FROM_REG (sbdl), + 0, +/*<<<*/ SCR_JUMPR ^ IFFALSE (MASK (M_IDENTIFY, 0x98)), + 32, + /* + ** It WAS an Identify message. + ** get it and ack it! + */ + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin), + SCR_CLR (SCR_ACK), + 0, + /* + ** Mask out the lun. + */ + SCR_REG_REG (sfbr, SCR_AND, 0x07), + 0, + SCR_RETURN, + 0, + /* + ** No message phase or no IDENTIFY message: + ** return 0. + */ +/*>>>*/ SCR_LOAD_SFBR (0), + 0, + SCR_RETURN, + 0, + +}/*-------------------------< RESEL_TAG >-------------------*/,{ + /* + ** come back to this point + ** to get a SIMPLE_TAG message + ** Wait for a MSG_IN phase. + */ +/*<<<*/ SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)), + 64, + /* + ** message phase + ** It's a trick - read the data + ** without acknowledging it. + */ + SCR_FROM_REG (sbdl), + 0, +/*<<<*/ SCR_JUMPR ^ IFFALSE (DATA (M_SIMPLE_TAG)), + 48, + /* + ** It WAS a SIMPLE_TAG message. + ** get it and ack it! + */ + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin), + SCR_CLR (SCR_ACK), + 0, + /* + ** Wait for the second byte (the tag) + */ +/*<<<*/ SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)), + 24, + /* + ** Get it and ack it! + */ + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin), + SCR_CLR (SCR_ACK|SCR_CARRY), + 0, + SCR_RETURN, + 0, + /* + ** No message phase or no SIMPLE_TAG message + ** or no second byte: return 0. + */ +/*>>>*/ SCR_LOAD_SFBR (0), + 0, + SCR_SET (SCR_CARRY), + 0, + SCR_RETURN, + 0, + +}/*-------------------------< DATA_IN >--------------------*/,{ +/* +** Because the size depends on the +** #define MAX_SCATTER parameter, +** it is filled in at runtime. +** +** SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)), +** PADDR (no_data), +** SCR_COPY (sizeof (u_long)), +** KVAR(SCRIPT_KVAR_JIFFIES), +** NADDR (header.stamp.data), +** SCR_MOVE_TBL ^ SCR_DATA_IN, +** offsetof (struct dsb, data[ 0]), +** +** ##===========< i=1; i========= +** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)), +** || PADDR (checkatn), +** || SCR_MOVE_TBL ^ SCR_DATA_IN, +** || offsetof (struct dsb, data[ i]), +** ##========================================== +** +** SCR_CALL, +** PADDR (checkatn), +** SCR_JUMP, +** PADDR (no_data), +*/ +0 +}/*-------------------------< DATA_OUT >-------------------*/,{ +/* +** Because the size depends on the +** #define MAX_SCATTER parameter, +** it is filled in at runtime. +** +** SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)), +** PADDR (no_data), +** SCR_COPY (sizeof (u_long)), +** KVAR(SCRIPT_KVAR_JIFFIES), +** NADDR (header.stamp.data), +** SCR_MOVE_TBL ^ SCR_DATA_OUT, +** offsetof (struct dsb, data[ 0]), +** +** ##===========< i=1; i========= +** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)), +** || PADDR (dispatch), +** || SCR_MOVE_TBL ^ SCR_DATA_OUT, +** || offsetof (struct dsb, data[ i]), +** ##========================================== +** +** SCR_CALL, +** PADDR (dispatch), +** SCR_JUMP, +** PADDR (no_data), +** +**--------------------------------------------------------- +*/ +0 /* was (u_long)&ident ? */ + +}/*-------------------------< ABORTTAG >-------------------*/,{ + /* + ** Abort a bad reselection. + ** Set the message to ABORT vs. ABORT_TAG + */ + SCR_LOAD_REG (scratcha, M_ABORT_TAG), + 0, + SCR_JUMPR ^ IFFALSE (CARRYSET), + 8, +}/*-------------------------< ABORT >----------------------*/,{ + SCR_LOAD_REG (scratcha, M_ABORT), + 0, + SCR_COPY (1), + RADDR (scratcha), + NADDR (msgout), + SCR_SET (SCR_ATN), + 0, + SCR_CLR (SCR_ACK), + 0, + /* + ** and send it. + ** we expect an immediate disconnect + */ + SCR_REG_REG (scntl2, SCR_AND, 0x7f), + 0, + SCR_MOVE_ABS (1) ^ SCR_MSG_OUT, + NADDR (msgout), + SCR_COPY (1), + RADDR (sfbr), + NADDR (lastmsg), + SCR_CLR (SCR_ACK|SCR_ATN), + 0, + SCR_WAIT_DISC, + 0, + SCR_JUMP, + PADDR (start), +}/*-------------------------< SNOOPTEST >-------------------*/,{ + /* + ** Read the variable. + */ + SCR_COPY (4), + NADDR(ncr_cache), + RADDR (scratcha), + /* + ** Write the variable. + */ + SCR_COPY (4), + RADDR (temp), + NADDR(ncr_cache), + /* + ** Read back the variable. + */ + SCR_COPY (4), + NADDR(ncr_cache), + RADDR (temp), +}/*-------------------------< SNOOPEND >-------------------*/,{ + /* + ** And stop. + */ + SCR_INT, + 99, +}/*--------------------------------------------------------*/ +}; + +/*========================================================== +** +** +** Fill in #define dependent parts of the script +** +** +**========================================================== +*/ + +void ncr_script_fill (struct script * scr) +{ + int i; + ncrcmd *p; + + p = scr->tryloop; + for (i=0; itryloop + sizeof (scr->tryloop)); + + p = scr->data_in; + + *p++ =SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)); + *p++ =PADDR (no_data); + *p++ =SCR_COPY (sizeof (u_long)); + *p++ =KVAR(SCRIPT_KVAR_JIFFIES); + *p++ =NADDR (header.stamp.data); + *p++ =SCR_MOVE_TBL ^ SCR_DATA_IN; + *p++ =offsetof (struct dsb, data[ 0]); + + for (i=1; idata_in + sizeof (scr->data_in)); + + p = scr->data_out; + + *p++ =SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_OUT)); + *p++ =PADDR (no_data); + *p++ =SCR_COPY (sizeof (u_long)); + *p++ =KVAR(SCRIPT_KVAR_JIFFIES); + *p++ =NADDR (header.stamp.data); + *p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT; + *p++ =offsetof (struct dsb, data[ 0]); + + for (i=1; idata_out + sizeof (scr->data_out)); +} + +/*========================================================== +** +** +** Copy and rebind a script. +** +** +**========================================================== +*/ + +static void ncr_script_copy_and_bind (struct script *script, ncb_p np) +{ + ncrcmd opcode, new, old, tmp1, tmp2; + ncrcmd *src, *dst, *start, *end; + int relocs; + + np->p_script = vtophys(np->script); + + src = script->start; + dst = np->script->start; + + start = src; + end = src + (sizeof (struct script) / 4); + + while (src < end) { + + *dst++ = opcode = *src++; + + /* + ** If we forget to change the length + ** in struct script, a field will be + ** padded with 0. This is an illegal + ** command. + */ + + if (opcode == 0) { + printf ("%s: ERROR0 IN SCRIPT at %d.\n", + ncr_name(np), (int) (src-start-1)); + DELAY (1000000); + }; + + if (DEBUG_FLAGS & DEBUG_SCRIPT) + printf ("%p: <%x>\n", + (src-1), (unsigned)opcode); + + /* + ** We don't have to decode ALL commands + */ + switch (opcode >> 28) { + + case 0xc: + /* + ** COPY has TWO arguments. + */ + relocs = 2; + tmp1 = src[0]; + if ((tmp1 & RELOC_MASK) == RELOC_KVAR) + tmp1 = 0; + tmp2 = src[1]; + if ((tmp2 & RELOC_MASK) == RELOC_KVAR) + tmp2 = 0; + if ((tmp1 ^ tmp2) & 3) { + printf ("%s: ERROR1 IN SCRIPT at %d.\n", + ncr_name(np), (int) (src-start-1)); + DELAY (1000000); + } + break; + + case 0x0: + /* + ** MOVE (absolute address) + */ + relocs = 1; + break; + + case 0x8: + /* + ** JUMP / CALL + ** dont't relocate if relative :-) + */ + if (opcode & 0x00800000) + relocs = 0; + else + relocs = 1; + break; + + case 0x4: + case 0x5: + case 0x6: + case 0x7: + relocs = 1; + break; + + default: + relocs = 0; + break; + }; + + if (relocs) { + while (relocs--) { + old = *src++; + + switch (old & RELOC_MASK) { + case RELOC_REGISTER: + new = (old & ~RELOC_MASK) + np->paddr; + break; + case RELOC_LABEL: + new = (old & ~RELOC_MASK) + np->p_script; + break; + case RELOC_SOFTC: + new = (old & ~RELOC_MASK) + vtophys(np); + break; + case RELOC_KVAR: + if (((old & ~RELOC_MASK) < + SCRIPT_KVAR_FIRST) || + ((old & ~RELOC_MASK) > + SCRIPT_KVAR_LAST)) + panic("ncr KVAR out of range"); + new = vtophys(script_kvars[old & + ~RELOC_MASK]); + break; + case 0: + /* Don't relocate a 0 address. */ + if (old == 0) { + new = old; + break; + } + /* fall through */ + default: + panic("ncr_script_copy_and_bind: weird relocation %x\n", old); + break; + } + + *dst++ = new; + } + } else + *dst++ = *src++; + + }; +} + +/*========================================================== +** +** +** Auto configuration: attach and init a host adapter. +** +** +**========================================================== +*/ + +#define MIN_ASYNC_PD 40 +#define MIN_SYNC_PD 20 + + +/* +** Linux host data structure +** +** The script area is allocated in the host data structure +** because kmalloc() returns NULL during scsi initialisations +** with Linux 1.2.X +*/ + +struct host_data { + struct ncb ncb_data; + struct script script_data; +}; + +/* +** Print something which allow to retreive the controler type, unit, +** target, lun concerned by a kernel message. +*/ + +#define PRINT_LUN(np, target, lun) \ +printf("%s-: ", ncr_name(np), (int) (target), (int) (lun)) + +static inline void PRINT_ADDR(Scsi_Cmnd *cmd) +{ + struct host_data *host_data = (struct host_data *) cmd->host->hostdata; + ncb_p np = &host_data->ncb_data; + if (np) PRINT_LUN(np, cmd->target, cmd->lun); +} + + +/* +** Host attach and initialisations. +** +** Allocate host data and ncb structure. +** Request IO region and remap MMIO region. +** Do chip initialization. +** Try with mmio. +** If mmio not possible (misconfigured cache), +** retry with io mapped. +** If all is OK, install interrupt handling and +** start the timer daemon. +*/ + +static int ncr_attach (Scsi_Host_Template *tpnt, int unit, ushort device_id, + u_char revision_id, int chip, u_int base, u_int io_port, + int irq, int bus, u_char device_fn) + +{ + struct host_data *host_data; + ncb_p np; + struct Scsi_Host *instance = 0; + u_long flags = 0; + +printf("ncr_attach: unit=%d chip=%d base=%x, io_port=%x, irq=%d\n", unit, chip, base, io_port, irq); + + /* + ** Allocate host_data structure + */ + if (!(instance = scsi_register(tpnt, sizeof(*host_data)))) + goto attach_error; + + /* + ** Initialize structure. + */ + instance->irq = irq; + host_data = (struct host_data *) instance->hostdata; + + np = &host_data->ncb_data; + bzero (np, sizeof (*np)); + np->unit = unit; + np->chip = chip; + np->device_id = device_id; + np->revision_id = revision_id; + np->script = &host_data->script_data; + + /* + ** Initialize timer structure + ** + */ + init_timer(&np->timer); + np->timer.data = (unsigned long) np; + np->timer.function = ncr53c8xx_timeout; + + /* + ** Try to map the controller chip to + ** virtual and physical memory. + */ + + np->paddr = base; + np->vaddr = base; + +#ifndef NCR_IOMAPPED + np->reg_remapped = (struct ncr_reg *) remap_pci_mem((u_long) base, (u_long) 128); + if (!np->reg_remapped) { + printf("%s: can't map memory mapped IO region\n", ncr_name(np)); + np->use_mmio = 0; + } + printf("%s: using memory mapped IO at virtual address 0x%lx\n", ncr_name(np), (u_long) np->reg_remapped); + np->use_mmio = 1; +#endif + /* + ** Try to map the controller chip into iospace. + */ + + request_region(io_port, 128, "ncr53c8xx"); + np->port = io_port; + + /* + ** Do chip dependent initialization. + */ + + switch (device_id) { + case PCI_DEVICE_ID_NCR_53C825: + case PCI_DEVICE_ID_NCR_53C875: + np->maxwide = 1; + break; + default: + np->maxwide = 0; + break; + } + + /* + ** Fill Linux host instance structure + */ +#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0) + instance->max_channel = 0; + instance->max_id = np->maxwide ? 16 : 8; + instance->max_lun = SCSI_NCR_MAX_LUN; +#endif +#ifndef NCR_IOMAPPED + instance->base = (char *) np->reg_remapped; +#endif + instance->io_port = io_port; + instance->n_io_port = 128; + instance->dma_channel = 0; +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,0,0) + instance->select_queue_depths = ncr53c8xx_select_queue_depths; +#endif + + /* + ** Patch script to physical addresses + */ + ncr_script_fill (&script0); + ncr_script_copy_and_bind (&script0, np); + np->ccb.p_ccb = vtophys (&np->ccb); + + /* + ** init data structure + */ + + np->jump_tcb.l_cmd = SCR_JUMP; + np->jump_tcb.l_paddr = NCB_SCRIPT_PHYS (np, abort); + + /* + ** Make the controller's registers available. + ** Now the INB INW INL OUTB OUTW OUTL macros + ** can be used safely. + */ + + np->reg = (struct ncr_reg*) np->vaddr; + +#ifndef NCR_IOMAPPED +retry_chip_init: +#endif + + /* + ** Get SCSI addr of host adapter (set by bios?). + */ + + np->myaddr = INB(nc_scid) & 0x07; + if (!np->myaddr) np->myaddr = SCSI_NCR_MYADDR; + + /* + ** Get the value of the chip's clock. + ** Find the right value for scntl3. + */ + + ncr_getclock (np); + + /* + ** Reset chip. + */ + + OUTW (nc_sien , 0); /* Disable scsi interrupts */ + OUTB (nc_dien , 0); /* Disable dma interrupts */ + + OUTB (nc_istat, SRST); + DELAY (1000); + OUTB (nc_istat, 0 ); + + /* + ** Reset chip, once again. + */ + + OUTB (nc_istat, SRST); + DELAY (1000); + OUTB (nc_istat, 0 ); + + /* + ** Now check the cache handling of the pci chipset. + */ + + if (ncr_snooptest (np)) { +#ifndef NCR_IOMAPPED + if (np->use_mmio) { +printf("%s: cache misconfigured, retrying with IO mapped at 0x%lx\n", + ncr_name(np), (u_long) np->port); + np->use_mmio = 0; + goto retry_chip_init; + } +#endif + printf ("CACHE INCORRECTLY CONFIGURED.\n"); + goto attach_error; + }; + + /* + ** Install the interrupt handler. + */ +#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70) +# ifdef SCSI_NCR_SHARE_IRQ + printf("%s: requesting shared irq %d (dev_id=0x%lx)\n", + ncr_name(np), irq, (u_long) np); + if (request_irq(irq, ncr53c8xx_intr, SA_SHIRQ, "53c8xx", np)) { +# else + if (request_irq(irq, ncr53c8xx_intr, SA_INTERRUPT, "53c8xx", NULL)) { +# endif +#else + if (request_irq(irq, ncr53c8xx_intr, SA_INTERRUPT, "53c8xx")) { +#endif + printf("%s: request irq %d failure\n", ncr_name(np), irq); + goto attach_error; + } + np->irq = irq; + + /* + ** After SCSI devices have been opened, we cannot + ** reset the bus safely, so we do it here. + ** Interrupt handler does the real work. + */ + + OUTB (nc_scntl1, CRST); + DELAY (1000); + + /* + ** Process the reset exception, + ** if interrupts are not enabled yet. + ** Then enable disconnects. + */ + save_flags(flags); cli(); + ncr_exception (np); + restore_flags(flags); + +#ifndef SCSI_NCR_NO_DISCONNECT + np->disc = 1; +#endif + + /* + ** The middle-level SCSI driver does not + ** wait devices to settle. + */ +#ifdef SCSI_NCR_SETTLE_TIME +#if SCSI_NCR_SETTLE_TIME > 2 + printf("%s: waiting for scsi devices to settle...\n", ncr_name(np)); +#endif +#if SCSI_NCR_SETTLE_TIME > 0 + DELAY(SCSI_NCR_SETTLE_TIME*1000000); +#endif +#endif + + /* + ** Now let the generic SCSI driver + ** look for the SCSI devices on the bus .. + */ + + /* + ** start the timeout daemon + */ + ncr_timeout (np); + np->lasttime=0; + + /* + ** use SIMPLE TAG messages by default + */ +#ifdef SCSI_NCR_ALWAYS_SIMPLE_TAG + np->order = M_SIMPLE_TAG; +#endif + + /* + ** Done. + */ + if (!the_template) { + the_template = instance->hostt; + first_host = instance; + } + + return 0; + +attach_error: + if (!instance) return -1; +#ifndef NCR_IOMAPPED + if (np->reg_remapped) { + printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->reg_remapped, 128); + unmap_pci_mem((vm_offset_t) np->reg_remapped, (u_long) 128); + } +#endif + if (np->port) { + printf("%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128); + release_region(np->port, 128); + } + scsi_unregister(instance); + + return -1; + } + +/*========================================================== +** +** +** Process pending device interrupts. +** +** +**========================================================== +*/ +int ncr_intr(np) + ncb_p np; +{ + int n = 0; + u_long flags; + + save_flags(flags); cli(); + + if (DEBUG_FLAGS & DEBUG_TINY) printf ("["); + +#ifdef SCSI_NCR_PARANOIA + if (INB(nc_istat) & (INTF|SIP|DIP)) { + /* + ** Repeat until no outstanding ints + */ + do { +#endif + ncr_exception (np); +#ifdef SCSI_NCR_PARANOIA + } while (INB(nc_istat) & (INTF|SIP|DIP)); + + n=1; + np->ticks = 5 * HZ; + }; +#endif + + if (DEBUG_FLAGS & DEBUG_TINY) printf ("]\n"); + + restore_flags(flags); + + return (n); +} + +/*========================================================== +** +** +** Start execution of a SCSI command. +** This is called from the generic SCSI driver. +** +** +**========================================================== +*/ +int ncr_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) +{ + struct Scsi_Host *host = cmd->host; +/* Scsi_Device *device = cmd->device; */ + struct host_data *host_data = (struct host_data *) host->hostdata; + ncb_p np = &host_data->ncb_data; + tcb_p tp = &np->target[cmd->target]; + + ccb_p cp; + lcb_p lp; + + int segments; + u_char qidx, nego, idmsg, *msgptr; + u_long msglen, msglen2; + u_long flags; + int xfer_direction; + + cmd->scsi_done = done; + cmd->host_scribble = NULL; + cmd->SCp.ptr = NULL; + cmd->SCp.buffer = NULL; + + /*--------------------------------------------- + ** + ** Reset SCSI bus + ** + ** Interrupt handler does the real work. + ** + **--------------------------------------------- + */ +#if 0 + if (flags & SCSI_RESET) { + OUTB (nc_scntl1, CRST); + DELAY (1000); + return(COMPLETE); + } +#endif + + /*--------------------------------------------- + ** + ** Some shortcuts ... + ** + **--------------------------------------------- + */ + if ((cmd->target == np->myaddr ) || + (cmd->target >= MAX_TARGET) || + (cmd->lun >= MAX_LUN )) { + return(DID_BAD_TARGET); + } + + + if (DEBUG_FLAGS & DEBUG_TINY) { + PRINT_ADDR(cmd); + printf ("CMD=%x ", cmd->cmnd[0]); + } + + /*--------------------------------------------------- + ** + ** Assign a ccb / bind cmd + ** If no free ccb, insert cmd into the waiting list. + ** + **---------------------------------------------------- + */ + save_flags(flags); cli(); + + if (!(cp=ncr_get_ccb (np, cmd->target, cmd->lun))) { + insert_into_waiting_list(np, cmd); + restore_flags(flags); + return(DID_OK); + } + cp->cmd = cmd; + + /*--------------------------------------------------- + ** + ** Enable tagged queue if asked by user + ** + **---------------------------------------------------- + */ +#ifdef SCSI_NCR_TAGGED_QUEUE_DISABLED + if (cmd->device && cmd->device->tagged_queue && + (lp = tp->lp[cmd->lun]) && (!lp->usetags)) { + ncr_setmaxtags (np, tp, SCSI_NCR_MAX_TAGS); + } +#endif + + /*--------------------------------------------------- + ** + ** timestamp + ** + **---------------------------------------------------- + */ + + bzero (&cp->phys.header.stamp, sizeof (struct tstamp)); + cp->phys.header.stamp.start = jiffies; + + /*---------------------------------------------------- + ** + ** Get device quirks from a speciality table. + ** + ** @GENSCSI@ + ** This should be a part of the device table + ** in "scsi_conf.c". + ** + **---------------------------------------------------- + */ + if (tp->quirks & QUIRK_UPDATE) { + tp->quirks = ncr_lookup ((char*) &tp->inqdata[0]); +#ifndef NCR_GETCC_WITHMSG + if (tp->quirks) { + PRINT_ADDR(cmd); + printf ("quirks=%x.\n", tp->quirks); + } +#endif + } + + /*--------------------------------------------------- + ** + ** negotiation required? + ** + ** Only SCSI-II devices. + ** To negotiate with SCSI-I devices is dangerous, since + ** Synchronous Negotiation protocol is optional, and + ** INQUIRY data do not contains capabilities in byte 7. + **---------------------------------------------------- + */ + + nego = 0; + + if (cmd->lun == 0 && (tp->inqdata[2] & 0x7) >= 2 && tp->inqdata[7]) { + /* + ** negotiate wide transfers ? + */ + + if (!tp->widedone) { + if (tp->inqdata[7] & INQ7_WIDE16) { + nego = NS_WIDE; + } else + tp->widedone=1; + }; + + /* + ** negotiate synchronous transfers? + */ + + if (!nego && !tp->period) { + if (SCSI_NCR_MAX_SYNC +#if defined (CDROM_ASYNC) + && ((tp->inqdata[0] & 0x1f) != 5) +#endif + && (tp->inqdata[7] & INQ7_SYNC)) { + nego = NS_SYNC; + } else { + tp->period =0xffff; + tp->sval = 0xe0; + PRINT_ADDR(cmd); + printf ("asynchronous.\n"); + }; + }; + }; + + /*--------------------------------------------------- + ** + ** choose a new tag ... + ** + **---------------------------------------------------- + */ + + if ((lp = tp->lp[cmd->lun]) && (lp->usetags)) { + /* + ** assign a tag to this ccb! + */ + while (!cp->tag) { + ccb_p cp2 = lp->next_ccb; + lp->lasttag = lp->lasttag % 255 + 1; + while (cp2 && cp2->tag != lp->lasttag) + cp2 = cp2->next_ccb; + if (cp2) continue; + cp->tag=lp->lasttag; + if (DEBUG_FLAGS & DEBUG_TAGS) { + PRINT_ADDR(cmd); + printf ("using tag #%d.\n", cp->tag); + } + } + } else { + cp->tag=0; + } + + /*---------------------------------------------------- + ** + ** Build the identify / tag / sdtr message + ** + **---------------------------------------------------- + */ + + idmsg = M_IDENTIFY | cmd->lun; + + if ((cp!=&np->ccb) && (np->disc)) + idmsg |= 0x40; + + msgptr = cp->scsi_smsg; + msglen = 0; + msgptr[msglen++] = idmsg; + + if (cp->tag) { + char tag; + + tag = np->order; + if (tag == 0) { + /* + ** Ordered write ops, unordered read ops. + */ + switch (cmd->cmnd[0]) { + case 0x08: /* READ_SMALL (6) */ + case 0x28: /* READ_BIG (10) */ + case 0xa8: /* READ_HUGE (12) */ + tag = M_SIMPLE_TAG; + break; + default: + tag = M_ORDERED_TAG; + } + } + /* + ** Have to force ordered tag to avoid timeouts + */ + if ((lp = tp->lp[cmd->lun]) && (lp->force_ordered_tag)) { + tag = M_ORDERED_TAG; + lp->force_ordered_tag = 0; + if (DEBUG_FLAGS & DEBUG_TAGS) { + PRINT_ADDR(cmd); + printf ("Ordered Queue Tag forced\n"); + } + } + msgptr[msglen++] = tag; + msgptr[msglen++] = cp -> tag; + } + + switch (nego) { + case NS_SYNC: + msgptr[msglen++] = M_EXTENDED; + msgptr[msglen++] = 3; + msgptr[msglen++] = M_X_SYNC_REQ; + msgptr[msglen++] = tp->maxoffs ? tp->minsync : 0; + msgptr[msglen++] = tp->maxoffs; + if (DEBUG_FLAGS & DEBUG_NEGO) { + PRINT_ADDR(cp->cmd); + printf ("sync msgout: "); + ncr_show_msg (&cp->scsi_smsg [msglen-5]); + printf (".\n"); + }; + break; + case NS_WIDE: + msgptr[msglen++] = M_EXTENDED; + msgptr[msglen++] = 2; + msgptr[msglen++] = M_X_WIDE_REQ; + msgptr[msglen++] = tp->usrwide; + if (DEBUG_FLAGS & DEBUG_NEGO) { + PRINT_ADDR(cp->cmd); + printf ("wide msgout: "); + ncr_show_msg (&cp->scsi_smsg [msglen-4]); + printf (".\n"); + }; + break; + }; + + /*---------------------------------------------------- + ** + ** Build the identify message for getcc. + ** + **---------------------------------------------------- + */ + + cp -> scsi_smsg2 [0] = idmsg; + msglen2 = 1; + + /*---------------------------------------------------- + ** + ** Build the data descriptors + ** + **---------------------------------------------------- + */ + + segments = ncr_scatter (cp, cp->cmd); + + if (segments < 0) { + ncr_free_ccb(np, cp); + restore_flags(flags); + return(DID_ERROR); + } + + /*---------------------------------------------------- + ** + ** Guess xfer direction. + ** Spare some CPU by testing here frequently opcode. + ** + **---------------------------------------------------- + */ + switch((int) cmd->cmnd[0]) { + case 0x08: /* READ(6) 08 */ + case 0x28: /* READ(10) 28 */ + xfer_direction = XferIn; + break; + case 0x0A: /* WRITE(6) 0A */ + case 0x2A: /* WRITE(10) 2A */ + xfer_direction = XferOut; + break; + default: + xfer_direction = guess_xfer_direction((int) cmd->cmnd[0]); + break; + } + + /*---------------------------------------------------- + ** + ** Set the SAVED_POINTER. + ** + **---------------------------------------------------- + */ + + switch (xfer_direction) { + default: + case XferIn: + cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_in); + cp->phys.header.goalp = cp->phys.header.savep +20 +segments*16; + break; + case XferOut: + cp->phys.header.savep = NCB_SCRIPT_PHYS (np, data_out); + cp->phys.header.goalp = cp->phys.header.savep +20 +segments*16; + break; + case XferNone: + cp->phys.header.savep = NCB_SCRIPT_PHYS (np, no_data); + cp->phys.header.goalp = cp->phys.header.savep; + break; + } + + cp->phys.header.lastp = cp->phys.header.savep; + + /*---------------------------------------------------- + ** + ** fill in ccb + ** + **---------------------------------------------------- + ** + ** + ** physical -> virtual backlink + ** Generic SCSI command + */ + cp->phys.header.cp = cp; + /* + ** Startqueue + */ + cp->phys.header.launch.l_paddr = NCB_SCRIPT_PHYS (np, select); + cp->phys.header.launch.l_cmd = SCR_JUMP; + /* + ** select + */ + cp->phys.select.sel_id = cmd->target; + cp->phys.select.sel_scntl3 = tp->wval; + cp->phys.select.sel_sxfer = tp->sval; + /* + ** message + */ + cp->phys.smsg.addr = CCB_PHYS (cp, scsi_smsg); + cp->phys.smsg.size = msglen; + + cp->phys.smsg2.addr = CCB_PHYS (cp, scsi_smsg2); + cp->phys.smsg2.size = msglen2; + /* + ** command + */ + cp->phys.cmd.addr = vtophys (&cmd->cmnd[0]); + cp->phys.cmd.size = cmd->cmd_len; + /* + ** sense command + */ + cp->phys.scmd.addr = CCB_PHYS (cp, sensecmd); + cp->phys.scmd.size = 6; + /* + ** patch requested size into sense command + */ + cp->sensecmd[0] = 0x03; + cp->sensecmd[1] = cmd->lun << 5; + cp->sensecmd[4] = sizeof(cmd->sense_buffer); + /* + ** sense data + */ + cp->phys.sense.addr = vtophys (&cmd->sense_buffer[0]); + cp->phys.sense.size = sizeof(cmd->sense_buffer); + /* + ** status + */ + cp->actualquirks = tp->quirks; + cp->host_status = nego ? HS_NEGOTIATE : HS_BUSY; + cp->scsi_status = S_ILLEGAL; + cp->parity_status = 0; + + cp->xerr_status = XE_OK; + cp->sync_status = tp->sval; + cp->nego_status = nego; + cp->wide_status = tp->wval; + + /*---------------------------------------------------- + ** + ** Critical region: start this job. + ** + **---------------------------------------------------- + */ + + /* + ** reselect pattern and activate this job. + */ + + cp->jump_ccb.l_cmd = (SCR_JUMP ^ IFFALSE (DATA (cp->tag))); + /* Compute a time limit bigger than the middle-level driver one */ + if (cmd->timeout_per_command > 0) + cp->tlimit = jiffies + cmd->timeout_per_command + NCR_TIMEOUT_INCREASE; + else + cp->tlimit = jiffies + 3600 * HZ; /* No timeout=one hour */ + cp->magic = CCB_MAGIC; + + /* + ** insert into start queue. + */ + + qidx = np->squeueput + 1; + if (qidx >= MAX_START) qidx=0; + np->squeue [qidx ] = NCB_SCRIPT_PHYS (np, idle); + np->squeue [np->squeueput] = CCB_PHYS (cp, phys); + np->squeueput = qidx; + + if(DEBUG_FLAGS & DEBUG_QUEUE) + printf ("%s: queuepos=%d tryoffset=%d.\n", ncr_name (np), + np->squeueput, + (unsigned)(np->script->startpos[0]- + (NCB_SCRIPT_PHYS (np, tryloop)))); + + /* + ** Script processor may be waiting for reselect. + ** Wake it up. + */ + OUTB (nc_istat, SIGP); + + /* + ** and reenable interrupts + */ + restore_flags(flags); + + /* + ** Command is successfully queued. + */ + + return(DID_OK); +} + +/*========================================================== +** +** +** Reset the SCSI BUS. +** This is called from the generic SCSI driver. +** +** +**========================================================== +*/ +int ncr_reset_bus (Scsi_Cmnd *cmd) +{ + struct Scsi_Host *host = cmd->host; +/* Scsi_Device *device = cmd->device; */ + struct host_data *host_data = (struct host_data *) host->hostdata; + ncb_p np = &host_data->ncb_data; + u_long flags; + + save_flags(flags); cli(); + + reset_waiting_list(np); + ncr_init(np, "scsi bus reset", HS_RESET); + +#ifndef SCSI_NCR_NO_DISCONNECT + np->disc = 1; +#endif + + restore_flags(flags); + + return SCSI_RESET_SUCCESS; +} + +/*========================================================== +** +** +** Abort an SCSI command. +** This is called from the generic SCSI driver. +** +** +**========================================================== +*/ +int ncr_abort_command (Scsi_Cmnd *cmd) +{ + struct Scsi_Host *host = cmd->host; +/* Scsi_Device *device = cmd->device; */ + struct host_data *host_data = (struct host_data *) host->hostdata; + ncb_p np = &host_data->ncb_data; + ccb_p cp; + u_long flags; + int found; + int retv; + + save_flags(flags); cli(); +/* + * First, look for the scsi command in the waiting list + */ + if (remove_from_waiting_list(np, cmd)) { + cmd->result = ScsiResult(DID_ABORT, 0); + cmd->scsi_done(cmd); + restore_flags(flags); + return SCSI_ABORT_SUCCESS; + } + +/* + * Then, look in the wakeup list + */ + for (found=0, cp=&np->ccb; cp; cp=cp->link_ccb) { + /* + ** look for the ccb of this command. + */ + if (cp->host_status == HS_IDLE) continue; + if (cp->cmd == cmd) { + found = 1; + break; + } + } + if (!found) { + restore_flags(flags); + return SCSI_ABORT_NOT_RUNNING; + } + + /* + ** Disable reselect. + ** Remove it from startqueue. + */ + cp->jump_ccb.l_cmd = (SCR_JUMP); + if (cp->phys.header.launch.l_paddr == NCB_SCRIPT_PHYS (np, select)) { + printf ("%s: abort ccb=%p (skip)\n", ncr_name (np), cp); + cp->phys.header.launch.l_paddr = NCB_SCRIPT_PHYS (np, skip); + } + + switch (cp->host_status) { + case HS_BUSY: + case HS_NEGOTIATE: + /* + ** still in start queue ? + */ + if (cp->phys.header.launch.l_paddr == NCB_SCRIPT_PHYS (np, skip)) { + retv = SCSI_ABORT_BUSY; + break; + } + /* fall through */ + case HS_DISCONNECT: + cp->host_status=HS_ABORTED; + cp->tag = 0; + /* + ** wakeup this ccb. + */ + ncr_complete (np, cp); + retv = SCSI_ABORT_SUCCESS; + break; + default: + cp->tag = 0; + /* + ** wakeup this ccb. + */ + ncr_complete (np, cp); + retv = SCSI_ABORT_SUCCESS; + break; + } + + restore_flags(flags); + + return retv; +} + +/*========================================================== +** +** Linux release module stuff. +** +** Called before unloading the module +** Detach the host. +** We have to free resources and halt the NCR chip +** +**========================================================== +*/ + +#ifdef MODULE +static int ncr_detach(ncb_p np, int irq) +{ + ccb_p cp; + tcb_p tp; + lcb_p lp; + int target, lun; + int i; + + printf("%s: releasing host resources\n", ncr_name(np)); + +/* +** Stop the ncr_timeout process +** Set release_stage to 1 and wait that ncr_timeout() set it to 2. +*/ + +#ifdef DEBUG + printf("%s: stopping the timer\n", ncr_name(np)); +#endif + np->release_stage = 1; + for (i = 50 ; i && np->release_stage != 2 ; i--) DELAY(100000); + if (np->release_stage != 2) + printf("%s: the timer seems to be already stopped\n", ncr_name(np)); + else np->release_stage = 2; + +/* +** Disable chip interrupts +*/ + +#ifdef DEBUG + printf("%s: disabling chip interrupts\n", ncr_name(np)); +#endif + OUTW (nc_sien , 0); + OUTB (nc_dien , 0); + +/* +** Free irq +*/ + +#ifdef DEBUG + printf("%s: freeing irq %d\n", ncr_name(np), irq); +#endif +#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70) +# ifdef SCSI_NCR_SHARE_IRQ + free_irq(irq, np); +# else + free_irq(irq, NULL); +# endif +#else + free_irq(irq); +#endif + + /* + ** Reset NCR chip + */ + + printf("%s: resetting chip\n", ncr_name(np)); + OUTB (nc_istat, SRST); + DELAY (1000); + OUTB (nc_istat, 0 ); + + /* + ** Release Memory mapped IO region and IO mapped region + */ + +#ifndef NCR_IOMAPPED +#ifdef DEBUG + printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->reg_remapped, 128); +#endif + unmap_pci_mem((vm_offset_t) np->reg_remapped, (u_long) 128); +#endif + +#ifdef DEBUG + printf("%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128); +#endif + release_region(np->port, 128); + + /* + ** Free allocated ccb(s) + */ + + while ((cp=np->ccb.link_ccb) != NULL) { + np->ccb.link_ccb = cp->link_ccb; + if (cp->host_status) { + printf("%s: shall free an active ccb (host_status=%d)\n", + ncr_name(np), cp->host_status); + } +#ifdef DEBUG + printf("%s: freeing ccb (%lx)\n", ncr_name(np), (u_long) cp); +#endif + m_free(cp, sizeof(*cp)); + } + + /* + ** Free allocated tp(s) + */ + + for (target = 0; target < MAX_TARGET ; target++) { + tp=&np->target[target]; + for (lun = 0 ; lun < MAX_LUN ; lun++) { + lp = tp->lp[lun]; + if (lp) { +#ifdef DEBUG + printf("%s: freeing lp (%lx)\n", ncr_name(np), (u_long) lp); +#endif + m_free(lp, sizeof(*lp)); + } + } + } + + printf("%s: host resources successfully released\n", ncr_name(np)); + + return 1; +} +#endif + +/*========================================================== +** +** +** Complete execution of a SCSI command. +** Signal completion to the generic SCSI driver. +** +** +**========================================================== +*/ + +void ncr_complete (ncb_p np, ccb_p cp) +{ + Scsi_Cmnd *cmd; + tcb_p tp; + lcb_p lp; + + /* + ** Sanity check + */ + + if (!cp || (cp->magic!=CCB_MAGIC) || !cp->cmd) return; + cp->magic = 1; + cp->tlimit= 0; + cmd = cp->cmd; + + /* + ** No Reselect anymore. + */ + cp->jump_ccb.l_cmd = (SCR_JUMP); + + /* + ** No starting. + */ + cp->phys.header.launch.l_paddr= NCB_SCRIPT_PHYS (np, idle); + + /* + ** timestamp + ** Optional, spare some CPU time + */ +#ifdef SCSI_NCR_PROFILE + ncb_profile (np, cp); +#endif + + if (DEBUG_FLAGS & DEBUG_TINY) + printf ("CCB=%lx STAT=%x/%x\n", (unsigned long)cp & 0xfff, + cp->host_status,cp->scsi_status); + + cmd = cp->cmd; + cp->cmd = NULL; + tp = &np->target[cmd->target]; + + /* + ** Check for parity errors. + */ + + if (cp->parity_status) { + PRINT_ADDR(cmd); + printf ("%d parity error(s), fallback.\n", cp->parity_status); + /* + ** fallback to asynch transfer. + */ + tp->usrsync=255; + tp->period = 0; + } + + /* + ** Check for extended errors. + */ + + if (cp->xerr_status != XE_OK) { + PRINT_ADDR(cmd); + switch (cp->xerr_status) { + case XE_EXTRA_DATA: + printf ("extraneous data discarded.\n"); + break; + case XE_BAD_PHASE: + printf ("illegal scsi phase (4/5).\n"); + break; + default: + printf ("extended error %d.\n", cp->xerr_status); + break; + } + if (cp->host_status==HS_COMPLETE) + cp->host_status = HS_FAIL; + } + + /* + ** Check the status. + */ + if ( (cp->host_status == HS_COMPLETE) + && (cp->scsi_status == S_GOOD)) { + + /* + ** All went well. + */ + cmd->result = ScsiResult(DID_OK, cp->scsi_status); + + /* + ** if (cp->phys.header.lastp != cp->phys.header.goalp)... + ** + ** @RESID@ + ** Could dig out the correct value for resid, + ** but it would be quite complicated. + ** + ** The ah1542.c driver sets it to 0 too ... + */ + + /* + ** Try to assign a ccb to this nexus + */ + ncr_alloc_ccb (np, cmd->target, cmd->lun); + + /* + ** On inquire cmd (0x12) save some data. + ** Clear questionnable capacities. + */ + if (cmd->lun == 0 && cmd->cmnd[0] == 0x12) { + if (np->unit < SCSI_NCR_MAX_HOST) { +#ifdef SCSI_NCR_FORCE_SYNC_NEGO + ((char *) cmd->request_buffer)[7] |= INQ7_SYNC; +#endif + ((char *) cmd->request_buffer)[7] &= + (target_capabilities[np->unit].and_map[cmd->target]); + } + bcopy ( cmd->request_buffer, + &tp->inqdata, + sizeof (tp->inqdata)); + + /* + ** set number of tags + */ + lp = tp->lp[cmd->lun]; +#ifndef SCSI_NCR_TAGGED_QUEUE_DISABLED + if (lp && !lp->usetags) { + ncr_setmaxtags (np, tp, SCSI_NCR_MAX_TAGS); + } +#endif + /* + ** prepare negotiation of synch and wide. + */ + ncr_negotiate (np, tp); + + /* + ** force quirks update before next command start + */ + tp->quirks |= QUIRK_UPDATE; + } + + tp->bytes += cp->data_len; + tp->transfers ++; + } else if ((cp->host_status == HS_COMPLETE) + && (cp->scsi_status == (S_SENSE|S_GOOD) || + cp->scsi_status == (S_SENSE|S_CHECK_COND))) { + + /* + ** Check condition code + */ + cmd->result = ScsiResult(DID_OK, S_CHECK_COND); + + if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) { + u_char * p = (u_char*) & cmd->sense_buffer; + int i; + printf ("\n%s: sense data:", ncr_name (np)); + for (i=0; i<14; i++) printf (" %x", *p++); + printf (".\n"); + } + + } else if ((cp->host_status == HS_COMPLETE) + && (cp->scsi_status == S_BUSY)) { + + /* + ** Target is busy. + */ + cmd->result = ScsiResult(DID_OK, cp->scsi_status); + + } else if ((cp->host_status == HS_SEL_TIMEOUT) + || (cp->host_status == HS_TIMEOUT)) { + + /* + ** No response + */ + cmd->result = ScsiResult(DID_TIME_OUT, cp->scsi_status); + + } else if (cp->host_status == HS_RESET) { + + /* + ** SCSI bus reset + */ + cmd->result = ScsiResult(DID_RESET, cp->scsi_status); + + } else if (cp->host_status == HS_ABORTED) { + + /* + ** Transfer aborted + */ + cmd->result = ScsiResult(DID_ABORT, cp->scsi_status); + + } else { + + /* + ** Other protocol messes + */ + PRINT_ADDR(cmd); + printf ("COMMAND FAILED (%x %x) @%p.\n", + cp->host_status, cp->scsi_status, cp); + + cmd->result = ScsiResult(DID_ERROR, cp->scsi_status); + } + + /* + ** trace output + */ + + if (tp->usrflag & UF_TRACE) { + u_char * p; + int i; + PRINT_ADDR(cmd); + printf (" CMD:"); + p = (u_char*) &cmd->cmnd[0]; + for (i=0; icmd_len; i++) printf (" %x", *p++); + + if (cp->host_status==HS_COMPLETE) { + switch (cp->scsi_status) { + case S_GOOD: + printf (" GOOD"); + break; + case S_CHECK_COND: + printf (" SENSE:"); + p = (u_char*) &cmd->sense_buffer; + for (i=0; i<14; i++) + printf (" %x", *p++); + break; + default: + printf (" STAT: %x\n", cp->scsi_status); + break; + } + } else printf (" HOSTERROR: %x", cp->host_status); + printf ("\n"); + } + + /* + ** Free this ccb + */ + ncr_free_ccb (np, cp); + + /* + ** requeue awaiting scsi commands + */ + if (np->waiting_list) requeue_waiting_list(np); + + /* + ** signal completion to generic driver. + */ + cmd->scsi_done (cmd); +} + +/*========================================================== +** +** +** Signal all (or one) control block done. +** +** +**========================================================== +*/ + +void ncr_wakeup (ncb_p np, u_long code) +{ + /* + ** Starting at the default ccb and following + ** the links, complete all jobs with a + ** host_status greater than "disconnect". + ** + ** If the "code" parameter is not zero, + ** complete all jobs that are not IDLE. + */ + + ccb_p cp = &np->ccb; + while (cp) { + switch (cp->host_status) { + + case HS_IDLE: + break; + + case HS_DISCONNECT: + if(DEBUG_FLAGS & DEBUG_TINY) printf ("D"); + /* fall through */ + + case HS_BUSY: + case HS_NEGOTIATE: + if (!code) break; + cp->host_status = code; + + /* fall through */ + + default: + ncr_complete (np, cp); + break; + }; + cp = cp -> link_ccb; + }; +} + +/*========================================================== +** +** +** Start NCR chip. +** +** +**========================================================== +*/ + +void ncr_init (ncb_p np, char * msg, u_long code) +{ + int i; + u_long usrsync; + u_char usrwide; +#if 0 + u_char burstlen; +#endif + + /* + ** Reset chip. + */ + + OUTB (nc_istat, SRST); + DELAY (10000); + + /* + ** Message. + */ + + if (msg) printf ("%s: restart (%s).\n", ncr_name (np), msg); + + /* + ** Clear Start Queue + */ + for (i=0;i squeue [i] = NCB_SCRIPT_PHYS (np, idle); + + /* + ** Start at first entry. + */ + + np->squeueput = 0; + np->script->startpos[0] = NCB_SCRIPT_PHYS (np, tryloop); + np->script->start0 [0] = SCR_INT ^ IFFALSE (0); + + /* + ** Wakeup all pending jobs. + */ + ncr_wakeup (np, code); + + /* + ** Init chip. + */ +/** NCR53C810 **/ + if (ChipDevice == PCI_DEVICE_ID_NCR_53C810 && ChipVersion == 0) { + OUTB(nc_dmode, 0x80); /* Set 8-transfer burst */ + } + else +/** NCR53C815 **/ + if (ChipDevice == PCI_DEVICE_ID_NCR_53C815) { + OUTB(nc_dmode, 0x80); /* Set 8-transfer burst */ + } + else +/** NCR53C825 **/ + if (ChipDevice == PCI_DEVICE_ID_NCR_53C825 && ChipVersion == 0) { + OUTB(nc_dmode, 0x80); /* Set 8-transfer burst */ + } + else +/** NCR53C810A or NCR53C860 **/ + if ((ChipDevice == PCI_DEVICE_ID_NCR_53C810 && ChipVersion >= 0x10) || + ChipDevice == PCI_DEVICE_ID_NCR_53C860) { + OUTB(nc_dmode, 0xc0); /* Set 16-transfer burst */ +#if 0 + OUTB(nc_ctest3, 0x01); /* Set write and invalidate */ + OUTB(nc_dcntl, 0xa1); /* Cache line size enable, */ + /* pre-fetch enable and 700 comp */ +#endif + } + else +/** NCR53C825A or NCR53C875 **/ + if ((ChipDevice == PCI_DEVICE_ID_NCR_53C825 && ChipVersion >= 0x10) || + ChipDevice == PCI_DEVICE_ID_NCR_53C875) { + OUTB(nc_dmode, 0xc0); /* Set 16-transfer burst */ + OUTB(nc_ctest5, 0x04); /* Set DMA FIFO to 88 */ +#if 0 + OUTB(nc_ctest5, 0x24); /* Set DMA FIFO to 536 */ + OUTB(nc_dmode, 0x40); /* Set 64-transfer burst */ + OUTB(nc_ctest3, 0x01); /* Set write and invalidate */ + OUTB(nc_dcntl, 0x81); /* Cache line size enable and 700 comp*/ +#endif + } +/** OTHERS **/ + else { + OUTB(nc_dmode, 0xc0); /* Set 16-transfer burst */ + } +#if 0 + burstlen = 0xc0; +#endif + + OUTB (nc_istat, 0 ); /* Remove Reset, abort ... */ + +#ifdef SCSI_NCR_DISABLE_PARITY_CHECK + OUTB (nc_scntl0, 0xc0 ); /* full arb., (no parity) */ +#else + OUTB (nc_scntl0, 0xca ); /* full arb., ena parity, par->ATN */ +#endif + + OUTB (nc_scntl1, 0x00 ); /* odd parity, and remove CRST!! */ + OUTB (nc_scntl3, np->rv_scntl3);/* timing prescaler */ + OUTB (nc_scid , RRE|np->myaddr);/* host adapter SCSI address */ + OUTW (nc_respid, 1ul<myaddr);/* id to respond to */ + OUTB (nc_istat , SIGP ); /* Signal Process */ +#if 0 + OUTB (nc_dmode , burstlen); /* Burst length = 2 .. 16 transfers */ +#endif + OUTB (nc_dcntl , NOCOM ); /* no single step mode, protect SFBR*/ + +#ifdef SCSI_NCR_DISABLE_MPARITY_CHECK + OUTB (nc_ctest4, 0x00 ); /* disable master parity checking */ +#else + OUTB (nc_ctest4, 0x08 ); /* enable master parity checking */ +#endif + + OUTB (nc_stest2, EXT ); /* Extended Sreq/Sack filtering */ + OUTB (nc_stest3, TE ); /* TolerANT enable */ + OUTB (nc_stime0, 0x0d ); /* HTH = disable STO = 0.4 sec. */ + /* 0.25 sec recommended for scsi 1 */ + + /* + ** Reinitialize usrsync. + ** Have to renegotiate synch mode. + */ + + usrsync = 255; + +#ifndef SCSI_NCR_FORCE_ASYNCHRONOUS + if (SCSI_NCR_MAX_SYNC) { + u_long period; + period =1000000/SCSI_NCR_MAX_SYNC; /* ns = 10e6 / kHz */ + if (period <= 11 * np->ns_sync) { + if (period < 4 * np->ns_sync) + usrsync = np->ns_sync; + else + usrsync = period / 4; + }; + }; +#endif + + /* + ** Reinitialize usrwide. + ** Have to renegotiate wide mode. + */ + + usrwide = (SCSI_NCR_MAX_WIDE); + if (usrwide > np->maxwide) usrwide=np->maxwide; + + /* + ** Disable disconnects. + */ + + np->disc = 0; + + /* + ** Fill in target structure. + */ + + for (i=0;itarget[i]; + + tp->sval = 0; + tp->wval = np->rv_scntl3; + + tp->usrsync = usrsync; + tp->usrwide = usrwide; + + ncr_negotiate (np, tp); + } + + /* + ** enable ints + */ + + OUTW (nc_sien , STO|HTH|MA|SGE|UDC|RST); + OUTB (nc_dien , MDPE|BF|ABRT|SSI|SIR|IID); + + /* + ** Start script processor. + */ + + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start)); +} + +/*========================================================== +** +** Prepare the negotiation values for wide and +** synchronous transfers. +** +**========================================================== +*/ + +static void ncr_negotiate (struct ncb* np, struct tcb* tp) +{ + /* + ** minsync unit is 4ns ! + */ + + u_long minsync = tp->usrsync; + + if (minsync < 25) minsync=25; + + /* + ** if not scsi 2 + ** don't believe FAST! + */ + + if ((minsync < 50) && (tp->inqdata[2] & 0x0f) < 2) + minsync=50; + + /* + ** our limit .. + */ + + if (minsync < np->ns_sync) + minsync = np->ns_sync; + + /* + ** divider limit + */ + + if (minsync > (np->ns_sync * 11) / 4) + minsync = 255; + + tp->minsync = minsync; + tp->maxoffs = (minsync<255 ? 8 : 0); + + /* + ** period=0: has to negotiate sync transfer + */ + + tp->period=0; + + /* + ** widedone=0: has to negotiate wide transfer + */ + tp->widedone=0; +} + +/*========================================================== +** +** Switch sync mode for current job and it's target +** +**========================================================== +*/ + +static void ncr_setsync (ncb_p np, ccb_p cp, u_char sxfer) +{ + Scsi_Cmnd *cmd; + tcb_p tp; + u_char target = INB (nc_ctest0)&7; + + assert (cp); + if (!cp) return; + + cmd = cp->cmd; + assert (cmd); + if (!cmd) return; + assert (target == (cmd->target & 0xf)); + + tp = &np->target[target]; + tp->period= sxfer&0xf ? ((sxfer>>5)+4) * np->ns_sync : 0xffff; + + if (tp->sval == sxfer) return; + tp->sval = sxfer; + + /* + ** Bells and whistles ;-) + */ + PRINT_ADDR(cmd); + if (sxfer & 0x0f) { + /* + ** Disable extended Sreq/Sack filtering + */ + if (tp->period <= 200) OUTB (nc_stest2, 0); + + printf ("%s%dns (%d Mb/sec) offset %d.\n", + tp->period<200 ? "FAST SCSI-2 ":"", + tp->period, + (((tp->wval & EWS)? 2:1)*1000+tp->period/2)/tp->period, + sxfer & 0x0f); + } else printf ("asynchronous.\n"); + + /* + ** set actual value and sync_status + */ + OUTB (nc_sxfer, sxfer); + np->sync_st = sxfer; + + /* + ** patch ALL ccbs of this target. + */ + for (cp = &np->ccb; cp; cp = cp->link_ccb) { + if (!cp->cmd) continue; + if (cp->cmd->target != target) continue; + cp->sync_status = sxfer; + }; +} + +/*========================================================== +** +** Switch wide mode for current job and it's target +** +**========================================================== +*/ + +static void ncr_setwide (ncb_p np, ccb_p cp, u_char wide) +{ + Scsi_Cmnd *cmd; + u_short target = INB (nc_ctest0)&7; + tcb_p tp; + u_char scntl3 = np->rv_scntl3 | (wide ? EWS : 0); + + assert (cp); + if (!cp) return; + + cmd = cp->cmd; + assert (cmd); + if (!cmd) return; + assert (target == (cmd->target & 0xf)); + + tp = &np->target[target]; + tp->widedone = wide+1; + if (tp->wval == scntl3) return; + tp->wval = scntl3; + + /* + ** Bells and whistles ;-) + */ + PRINT_ADDR(cmd); + if (scntl3 & EWS) + printf ("WIDE SCSI (16 bit) enabled.\n"); + else + printf ("WIDE SCSI disabled.\n"); + + /* + ** set actual value and sync_status + */ + OUTB (nc_scntl3, scntl3); + np->wide_st = scntl3; + + /* + ** patch ALL ccbs of this target. + */ + for (cp = &np->ccb; cp; cp = cp->link_ccb) { + if (!cp->cmd) continue; + if (cp->cmd->target != target) continue; + cp->wide_status = scntl3; + }; +} + +/*========================================================== +** +** Switch tagged mode for a target. +** +**========================================================== +*/ + +static void ncr_setmaxtags (ncb_p np, tcb_p tp, u_long usrtags) +{ + int l; + tp->usrtags = usrtags; + for (l=0; llp[l]; + if (!lp) continue; + ncr_settags (tp, lp); + if (lp->usetags > 0) { + PRINT_LUN(np, tp - np->target, l); + printf("using tagged command queueing, up to %d cmds/lun\n", lp->usetags); + } + }; +} + +static void ncr_settags (tcb_p tp, lcb_p lp) +{ + u_char reqtags, tmp; + + if ((!tp) || (!lp)) return; + + /* + ** only devices conformant to ANSI Version >= 2 + ** only devices capable of tagges commands + ** only disk devices + ** only if enabled by user .. + */ + if (( tp->inqdata[2] & 0x7) >= 2 && + ( tp->inqdata[7] & INQ7_QUEUE) && ((tp->inqdata[0] & 0x1f)==0x00) + && tp->usrtags) { + reqtags = tp->usrtags; + if (lp->actlink <= 1) + lp->usetags=reqtags; + } else { + reqtags = 1; + if (lp->actlink <= 1) + lp->usetags=0; + }; + + /* + ** don't announce more than available. + */ + tmp = lp->actccbs; + if (tmp > reqtags) tmp = reqtags; + lp->reqlink = tmp; + + /* + ** don't discard if announced. + */ + tmp = lp->actlink; + if (tmp < reqtags) tmp = reqtags; + lp->reqccbs = tmp; +} + +/*---------------------------------------------------- +** +** handle user commands +** +**---------------------------------------------------- +*/ + +#ifdef SCSI_NCR_USER_COMMAND + +static void ncr_usercmd (ncb_p np) +{ + u_char t; + tcb_p tp; + + switch (np->user.cmd) { + + case 0: return; + + case UC_SETSYNC: + for (t=0; tuser.target>>t)&1)) continue; + tp = &np->target[t]; + tp->usrsync = np->user.data; + ncr_negotiate (np, tp); + }; + break; + + case UC_SETTAGS: + if (np->user.data > SCSI_NCR_MAX_TAGS) + np->user.data = SCSI_NCR_MAX_TAGS; + for (t=0; tuser.target>>t)&1)) continue; + ncr_setmaxtags (np, &np->target[t], np->user.data); + }; + np->disc = 1; + break; + + case UC_SETDEBUG: +#ifdef SCSI_NCR_DEBUG + ncr_debug = np->user.data; +#endif + break; + + case UC_SETORDER: + np->order = np->user.data; + break; + + case UC_SETWIDE: + for (t=0; tuser.target>>t)&1)) continue; + tp = &np->target[t]; + size = np->user.data; + if (size > np->maxwide) size=np->maxwide; + tp->usrwide = size; + ncr_negotiate (np, tp); + }; + break; + + case UC_SETFLAG: + for (t=0; tuser.target>>t)&1)) continue; + tp = &np->target[t]; + tp->usrflag = np->user.data; + }; + break; + + case UC_CLEARPROF: + bzero(&np->profile, sizeof(np->profile)); + break; + } + np->user.cmd=0; +} +#endif + + + +/*========================================================== +** +** +** ncr timeout handler. +** +** +**========================================================== +** +** Misused to keep the driver running when +** interrupts are not configured correctly. +** +**---------------------------------------------------------- +*/ + +static void ncr_timeout (ncb_p np) +{ + u_long thistime = jiffies; + u_long count = 0; + long signed t; + ccb_p cp; + u_long flags; + + /* + ** If release process in progress, let's go + ** Set the release stage from 1 to 2 to synchronize + ** with the release process. + **/ + + if (np->release_stage) { + if (np->release_stage == 1) np->release_stage = 2; + return; + } + + np->timer.expires = +#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0) + jiffies + +#endif + SCSI_NCR_TIMER_INTERVAL; + + add_timer(&np->timer); + + if (np->lasttime + HZ < thistime) { + /* + ** block ncr interrupts + */ + save_flags(flags); cli(); + + np->lasttime = thistime; + + /* + ** Reset profile data to avoid ugly overflow + ** (Limited to 1024 GB for 32 bit architecture) + */ + if (np->profile.num_kbytes > (~0UL >> 2)) + bzero(&np->profile, sizeof(np->profile)); + + /*---------------------------------------------------- + ** + ** handle ncr chip timeouts + ** + ** Assumption: + ** We have a chance to arbitrate for the + ** SCSI bus at least every 10 seconds. + ** + **---------------------------------------------------- + */ + + t = (thistime - np->heartbeat) / HZ; + + if (t<2) np->latetime=0; else np->latetime++; + if (np->latetime>5) { + /* + ** If there are no requests, the script + ** processor will sleep on SEL_WAIT_RESEL. + ** But we have to check whether it died. + ** Let's wake it up. + */ + OUTB (nc_istat, SIGP); + } + if (np->latetime>10) { + /* + ** Although we tried to wake it up, + ** the script processor didn't respond. + ** + ** May be a target is hanging, + ** or another initator lets a tape device + ** rewind with disconnect disabled :-( + ** + ** We won't accept that. + */ + if (INB (nc_sbcl) & CBSY) + OUTB (nc_scntl1, CRST); + DELAY (1000); + ncr_init (np, "ncr dead ?", HS_TIMEOUT); +#ifndef SCSI_NCR_NO_DISCONNECT + np->disc = 1; +#endif + np->heartbeat = thistime; + } + + /*---------------------------------------------------- + ** + ** should handle ccb timeouts + ** Let the middle scsi driver manage timeouts. + **---------------------------------------------------- + */ + + for (cp=&np->ccb; cp; cp=cp->link_ccb) { + /* + ** look for timed out ccbs. + */ + if (!cp->host_status) continue; + count++; + /* + ** Have to force ordered tag to avoid timeouts + */ + if (cp->cmd && cp->tlimit <= + thistime + NCR_TIMEOUT_INCREASE + SCSI_NCR_TIMEOUT_ALERT) { + lcb_p lp; + lp = np->target[cp->cmd->target].lp[cp->cmd->lun]; + if (lp && !lp->force_ordered_tag) { + lp->force_ordered_tag = 1; + } + } +/* +** Let the middle scsi driver manage timeouts +*/ +#if 0 + if (cp->tlimit > thistime) continue; + + /* + ** Disable reselect. + ** Remove it from startqueue. + */ + cp->jump_ccb.l_cmd = (SCR_JUMP); + if (cp->phys.header.launch.l_paddr == + NCB_SCRIPT_PHYS (np, select)) { + printf ("%s: timeout ccb=%p (skip)\n", + ncr_name (np), cp); + cp->phys.header.launch.l_paddr + = NCB_SCRIPT_PHYS (np, skip); + }; + + switch (cp->host_status) { + + case HS_BUSY: + case HS_NEGOTIATE: + /* + ** still in start queue ? + */ + if (cp->phys.header.launch.l_paddr == + NCB_SCRIPT_PHYS (np, skip)) + continue; + + /* fall through */ + case HS_DISCONNECT: + cp->host_status=HS_TIMEOUT; + }; + cp->tag = 0; + + /* + ** wakeup this ccb. + */ + ncr_complete (np, cp); +#endif + } + restore_flags(flags); + } + +#ifdef SCSI_NCR_BROKEN_INTR + if (INB(nc_istat) & (INTF|SIP|DIP)) { + + /* + ** Process pending interrupts. + */ + save_flags(flags); cli(); + if (DEBUG_FLAGS & DEBUG_TINY) printf ("{"); + ncr_exception (np); + if (DEBUG_FLAGS & DEBUG_TINY) printf ("}"); + restore_flags(flags); + } +#endif /* SCSI_NCR_BROKEN_INTR */ +} + +/*========================================================== +** +** +** ncr chip exception handler. +** +** +**========================================================== +*/ + +void ncr_exception (ncb_p np) +{ + u_char istat, dstat; + u_short sist; + u_int32 dsp, dsa; + int script_ofs; + int i; + + /* + ** interrupt on the fly ? + */ + while ((istat = INB (nc_istat)) & INTF) { + if (DEBUG_FLAGS & DEBUG_TINY) printf ("F"); + OUTB (nc_istat, (istat & SIGP) | INTF); + np->profile.num_fly++; + ncr_wakeup (np, 0); + }; + + if (!(istat & (SIP|DIP))) return; + + /* + ** Steinbach's Guideline for Systems Programming: + ** Never test for an error condition you don't know how to handle. + */ + + dstat = INB (nc_dstat); + sist = INW (nc_sist) ; + np->profile.num_int++; + + if (DEBUG_FLAGS & DEBUG_TINY) + printf ("<%d|%x:%x|%x:%x>", + (int)INB(nc_scr0), + dstat,sist, + (unsigned)INL(nc_dsp), + (unsigned)INL(nc_dbc)); + if ((dstat==DFE) && (sist==PAR)) return; + +/*========================================================== +** +** First the normal cases. +** +**========================================================== +*/ + /*------------------------------------------- + ** SCSI reset + **------------------------------------------- + */ + + if (sist & RST) { + ncr_init (np, bootverbose ? "scsi reset" : NULL, HS_RESET); + return; + }; + + /*------------------------------------------- + ** selection timeout + ** + ** IID excluded from dstat mask! + ** (chip bug) + **------------------------------------------- + */ + + if ((sist & STO) && + !(sist & (GEN|HTH|MA|SGE|UDC|RST|PAR)) && + !(dstat & (MDPE|BF|ABRT|SIR))) { + ncr_int_sto (np); + return; + }; + + /*------------------------------------------- + ** Phase mismatch. + **------------------------------------------- + */ + + if ((sist & MA) && + !(sist & (STO|GEN|HTH|SGE|UDC|RST|PAR)) && + !(dstat & (MDPE|BF|ABRT|SIR|IID))) { + ncr_int_ma (np); + return; + }; + + /*---------------------------------------- + ** move command with length 0 + **---------------------------------------- + */ + + if ((dstat & IID) && + !(sist & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) && + !(dstat & (MDPE|BF|ABRT|SIR)) && + ((INL(nc_dbc) & 0xf8000000) == SCR_MOVE_TBL)) { + /* + ** Target wants more data than available. + ** The "no_data" script will do it. + */ + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, no_data)); + return; + }; + + /*------------------------------------------- + ** Programmed interrupt + **------------------------------------------- + */ + + if ((dstat & SIR) && + !(sist & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) && + !(dstat & (MDPE|BF|ABRT|IID)) && + (INB(nc_dsps) <= SIR_MAX)) { + ncr_int_sir (np); + return; + }; + + /*======================================== + ** do the register dump + **======================================== + */ + if (jiffies - np->regtime > 10*HZ) { + int i; + np->regtime = jiffies; + for (i=0; iregdump); i++) + ((char*)&np->regdump)[i] = INB_OFF(i); + np->regdump.nc_dstat = dstat; + np->regdump.nc_sist = sist; + }; + + /*========================================= + ** log message for real hard errors + **========================================= + + "ncr0 targ 0?: ERROR (ds:si) (so-si-sd) (sxfer/scntl3) @ (dsp:dbc)." + " reg: r0 r1 r2 r3 r4 r5 r6 ..... rf." + + exception register: + ds: dstat + si: sist + + SCSI bus lines: + so: control lines as driver by NCR. + si: control lines as seen by NCR. + sd: scsi data lines as seen by NCR. + + wide/fastmode: + sxfer: (see the manual) + scntl3: (see the manual) + + current script command: + dsp: script adress (relative to start of script). + dbc: first word of script command. + + First 16 register of the chip: + r0..rf + + ============================================= + */ + + dsp = (unsigned) INL (nc_dsp); + dsa = (unsigned) INL (nc_dsa); + + script_ofs = dsp - np->p_script; + + printf ("%s:%d: ERROR (%x:%x) (%x-%x-%x) (%x/%x) @ (%x:%08x).\n", + ncr_name (np), (unsigned)INB (nc_ctest0)&0x0f, dstat, sist, + (unsigned)INB (nc_socl), (unsigned)INB (nc_sbcl), (unsigned)INB (nc_sbdl), + (unsigned)INB (nc_sxfer),(unsigned)INB (nc_scntl3), script_ofs, + (unsigned) INL (nc_dbc)); + + if (((script_ofs & 3) == 0) && + (unsigned)script_ofs < sizeof(struct script)) { + printf ("\tscript cmd = %08x\n", + (int) *(ncrcmd *)((char*)np->script +script_ofs)); + } + + printf ("\treg:\t"); + for (i=0; i<16;i++) + printf (" %02x", (unsigned)INB_OFF(i)); + printf (".\n"); + + /*---------------------------------------- + ** clean up the dma fifo + **---------------------------------------- + */ + + if ( (INB(nc_sstat0) & (ILF|ORF|OLF) ) || + (INB(nc_sstat1) & (FF3210) ) || + (INB(nc_sstat2) & (ILF1|ORF1|OLF1)) || /* wide .. */ + !(dstat & DFE)) { + printf ("%s: have to clear fifos.\n", ncr_name (np)); + OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */ + OUTB (nc_ctest3, CLF); /* clear dma fifo */ + } + + /*---------------------------------------- + ** handshake timeout + **---------------------------------------- + */ + + if (sist & HTH) { + printf ("%s: handshake timeout\n", ncr_name(np)); + OUTB (nc_scntl1, CRST); + DELAY (1000); + OUTB (nc_scntl1, 0x00); + OUTB (nc_scr0, HS_FAIL); + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup)); + return; + } + + /*---------------------------------------- + ** unexpected disconnect + **---------------------------------------- + */ + + if ((sist & UDC) && + !(sist & (STO|GEN|HTH|MA|SGE|RST|PAR)) && + !(dstat & (MDPE|BF|ABRT|SIR|IID))) { + OUTB (nc_scr0, HS_UNEXPECTED); + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup)); + return; + }; + + /*---------------------------------------- + ** cannot disconnect + **---------------------------------------- + */ + + if ((dstat & IID) && + !(sist & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) && + !(dstat & (MDPE|BF|ABRT|SIR)) && + ((INL(nc_dbc) & 0xf8000000) == SCR_WAIT_DISC)) { + /* + ** Unexpected data cycle while waiting for disconnect. + */ + if (INB(nc_sstat2) & LDSC) { + /* + ** It's an early reconnect. + ** Let's continue ... + */ + OUTB (nc_dcntl, (STD|NOCOM)); + /* + ** info message + */ + printf ("%s: INFO: LDSC while IID.\n", + ncr_name (np)); + return; + }; + printf ("%s: target %d doesn't release the bus.\n", + ncr_name (np), (int)INB (nc_ctest0)&0x0f); + /* + ** return without restarting the NCR. + ** timeout will do the real work. + */ + return; + }; + + /*---------------------------------------- + ** single step + **---------------------------------------- + */ + + if ((dstat & SSI) && + !(sist & (STO|GEN|HTH|MA|SGE|UDC|RST|PAR)) && + !(dstat & (MDPE|BF|ABRT|SIR|IID))) { + OUTB (nc_dcntl, (STD|NOCOM)); + return; + }; + +/* +** @RECOVER@ HTH, SGE, ABRT. +** +** We should try to recover from these interrupts. +** They may occur if there are problems with synch transfers, or +** if targets are switched on or off while the driver is running. +*/ + + if (sist & SGE) { + OUTB (nc_ctest3, CLF); /* clear scsi offsets */ + } + + /* + ** Freeze controller to be able to read the messages. + */ + + if (DEBUG_FLAGS & DEBUG_FREEZE) { + unsigned char val; + for (i=0; i<0x60; i++) { + switch (i%16) { + + case 0: + printf ("%s: reg[%d0]: ", + ncr_name(np),i/16); + break; + case 4: + case 8: + case 12: + printf (" "); + break; + }; + val = INB_OFF(i); + printf (" %x%x", val/16, val%16); + if (i%16==15) printf (".\n"); + } + + del_timer(&np->timer); + + printf ("%s: halted!\n", ncr_name(np)); + /* + ** don't restart controller ... + */ + OUTB (nc_istat, SRST); + return; + }; + +#ifdef NCR_FREEZE + /* + ** Freeze system to be able to read the messages. + */ + printf ("ncr: fatal error: system halted - press reset to reboot ..."); + cli(); + for (;;); +#endif + + /* + ** sorry, have to kill ALL jobs ... + */ + + ncr_init (np, "fatal error", HS_FAIL); +#ifndef SCSI_NCR_NO_DISCONNECT + np->disc = 1; +#endif +} + +/*========================================================== +** +** ncr chip exception handler for selection timeout +** +**========================================================== +** +** There seems to be a bug in the 53c810. +** Although a STO-Interrupt is pending, +** it continues executing script commands. +** But it will fail and interrupt (IID) on +** the next instruction where it's looking +** for a valid phase. +** +**---------------------------------------------------------- +*/ + +void ncr_int_sto (ncb_p np) +{ + u_long dsa, scratcha, diff; + ccb_p cp; + if (DEBUG_FLAGS & DEBUG_TINY) printf ("T"); + + /* + ** look for ccb and set the status. + */ + + dsa = INL (nc_dsa); + cp = &np->ccb; + while (cp && (CCB_PHYS (cp, phys) != dsa)) + cp = cp->link_ccb; + + if (cp) { + cp-> host_status = HS_SEL_TIMEOUT; + ncr_complete (np, cp); + }; + + /* + ** repair start queue + */ + + scratcha = INL (nc_scratcha); + diff = scratcha - NCB_SCRIPT_PHYS (np, tryloop); + +/* assert ((diff <= MAX_START * 20) && !(diff % 20));*/ + + if ((diff <= MAX_START * 20) && !(diff % 20)) { + np->script->startpos[0] = scratcha; + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start)); + return; + }; + ncr_init (np, "selection timeout", HS_FAIL); +#ifndef SCSI_NCR_NO_DISCONNECT + np->disc = 1; +#endif +} + +/*========================================================== +** +** +** ncr chip exception handler for phase errors. +** +** +**========================================================== +** +** We have to construct a new transfer descriptor, +** to transfer the rest of the current block. +** +**---------------------------------------------------------- +*/ + +static void ncr_int_ma (ncb_p np) +{ + u_int32 dbc; + u_int32 rest; + u_int32 dsa; + u_int32 dsp; + u_int32 nxtdsp; + u_int32 *vdsp; + u_int32 oadr, olen; + u_int32 *tblp; + ncrcmd *newcmd; + u_char cmd, sbcl, delta, ss0, ss2; + ccb_p cp; + + dsp = INL (nc_dsp); + dsa = INL (nc_dsa); + dbc = INL (nc_dbc); + ss0 = INB (nc_sstat0); + ss2 = INB (nc_sstat2); + sbcl= INB (nc_sbcl); + + cmd = dbc >> 24; + rest= dbc & 0xffffff; + delta=(INB (nc_dfifo) - rest) & 0x7f; + + /* + ** The data in the dma fifo has not been transfered to + ** the target -> add the amount to the rest + ** and clear the data. + ** Check the sstat2 register in case of wide transfer. + */ + + if (! (INB(nc_dstat) & DFE)) rest += delta; + if (ss0 & OLF) rest++; + if (ss0 & ORF) rest++; + if (INB(nc_scntl3) & EWS) { + if (ss2 & OLF1) rest++; + if (ss2 & ORF1) rest++; + }; + OUTB (nc_ctest3, CLF ); /* clear dma fifo */ + OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */ + + /* + ** locate matching cp + */ + dsa = INL (nc_dsa); + cp = &np->ccb; + while (cp && (CCB_PHYS (cp, phys) != dsa)) + cp = cp->link_ccb; + + if (!cp) { + printf ("%s: SCSI phase error fixup: CCB already dequeued (0x%08lx)\n", + ncr_name (np), (u_long) np->header.cp); + return; + } + if (cp != np->header.cp) { + printf ("%s: SCSI phase error fixup: CCB address mismatch (0x%08lx != 0x%08lx)\n", + ncr_name (np), (u_long) cp, (u_long) np->header.cp); +/* return;*/ + } + + /* + ** find the interrupted script command, + ** and the address at which to continue. + */ + + if (dsp == vtophys (&cp->patch[2])) { + vdsp = &cp->patch[0]; + nxtdsp = vdsp[3]; + } else if (dsp == vtophys (&cp->patch[6])) { + vdsp = &cp->patch[4]; + nxtdsp = vdsp[3]; + } else { + vdsp = (u_int32 *) ((char*)np->script - np->p_script + dsp -8); + nxtdsp = dsp; + }; + + /* + ** log the information + */ + if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE)) { + printf ("P%x%x ",cmd&7, sbcl&7); + printf ("RL=%d D=%d SS0=%x ", + (unsigned) rest, (unsigned) delta, ss0); + }; + if (DEBUG_FLAGS & DEBUG_PHASE) { + printf ("\nCP=%p CP2=%p DSP=%x NXT=%x VDSP=%p CMD=%x ", + cp, np->header.cp, + (unsigned)dsp, + (unsigned)nxtdsp, vdsp, cmd); + }; + + /* + ** get old startaddress and old length. + */ + + oadr = vdsp[1]; + + if (cmd & 0x10) { /* Table indirect */ + tblp = (u_int32 *) ((char*) &cp->phys + oadr); + olen = tblp[0]; + oadr = tblp[1]; + } else { + tblp = (u_int32 *) 0; + olen = vdsp[0] & 0xffffff; + }; + + if (DEBUG_FLAGS & DEBUG_PHASE) { + printf ("OCMD=%x\nTBLP=%p OLEN=%x OADR=%x\n", + (unsigned) (vdsp[0] >> 24), + tblp, + (unsigned) olen, + (unsigned) oadr); + }; + + /* + ** if old phase not dataphase, leave here. + */ + + if (cmd != (vdsp[0] >> 24)) { + PRINT_ADDR(cp->cmd); + printf ("internal error: cmd=%02x != %02x=(vdsp[0] >> 24)\n", + (unsigned)cmd, (unsigned)vdsp[0] >> 24); + + return; + } + if (cmd & 0x06) { + PRINT_ADDR(cp->cmd); + printf ("phase change %x-%x %d@%08x resid=%d.\n", + cmd&7, sbcl&7, (unsigned)olen, + (unsigned)oadr, (unsigned)rest); + + OUTB (nc_dcntl, (STD|NOCOM)); + return; + }; + + /* + ** choose the correct patch area. + ** if savep points to one, choose the other. + */ + + newcmd = cp->patch; + if (cp->phys.header.savep == vtophys (newcmd)) newcmd+=4; + + /* + ** fillin the commands + */ + + newcmd[0] = ((cmd & 0x0f) << 24) | rest; + newcmd[1] = oadr + olen - rest; + newcmd[2] = SCR_JUMP; + newcmd[3] = nxtdsp; + + if (DEBUG_FLAGS & DEBUG_PHASE) { + PRINT_ADDR(cp->cmd); + printf ("newcmd[%d] %x %x %x %x.\n", + (int) (newcmd - cp->patch), + (unsigned)newcmd[0], + (unsigned)newcmd[1], + (unsigned)newcmd[2], + (unsigned)newcmd[3]); + } + /* + ** fake the return address (to the patch). + ** and restart script processor at dispatcher. + */ + np->profile.num_break++; + OUTL (nc_temp, vtophys (newcmd)); + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch)); +} + +/*========================================================== +** +** +** ncr chip exception handler for programmed interrupts. +** +** +**========================================================== +*/ + +static int ncr_show_msg (u_char * msg) +{ + u_char i; + printf ("%x",*msg); + if (*msg==M_EXTENDED) { + for (i=1;i<8;i++) { + if (i-1>msg[1]) break; + printf ("-%x",msg[i]); + }; + return (i+1); + } else if ((*msg & 0xf0) == 0x20) { + printf ("-%x",msg[1]); + return (2); + }; + return (1); +} + +void ncr_int_sir (ncb_p np) +{ + u_char chg, ofs, per, fak, wide; + u_char num = INB (nc_dsps); + ccb_p cp=0; + u_long dsa; + u_char target = INB (nc_ctest0) & 7; + tcb_p tp = &np->target[target]; + int i; + if (DEBUG_FLAGS & DEBUG_TINY) printf ("I#%d", num); + + switch (num) { + case SIR_SENSE_RESTART: + case SIR_STALL_RESTART: + break; + + default: + /* + ** lookup the ccb + */ + dsa = INL (nc_dsa); + cp = &np->ccb; + while (cp && (CCB_PHYS (cp, phys) != dsa)) + cp = cp->link_ccb; + + assert (cp); + if (!cp) + goto out; + assert (cp == np->header.cp); + if (cp != np->header.cp) + goto out; + } + + switch (num) { + +/*-------------------------------------------------------------------- +** +** Processing of interrupted getcc selects +** +**-------------------------------------------------------------------- +*/ + + case SIR_SENSE_RESTART: + /*------------------------------------------ + ** Script processor is idle. + ** Look for interrupted "check cond" + **------------------------------------------ + */ + + if (DEBUG_FLAGS & DEBUG_RESTART) + printf ("%s: int#%d",ncr_name (np),num); + cp = (ccb_p) 0; + for (i=0; itarget[i]; + if (DEBUG_FLAGS & DEBUG_RESTART) printf ("+"); + cp = tp->hold_cp; + if (!cp) continue; + if (DEBUG_FLAGS & DEBUG_RESTART) printf ("+"); + if ((cp->host_status==HS_BUSY) && + (cp->scsi_status==S_CHECK_COND)) + break; + if (DEBUG_FLAGS & DEBUG_RESTART) printf ("- (remove)"); + tp->hold_cp = cp = (ccb_p) 0; + }; + + if (cp) { + if (DEBUG_FLAGS & DEBUG_RESTART) + printf ("+ restart job ..\n"); + OUTL (nc_dsa, CCB_PHYS (cp, phys)); + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, getcc)); + return; + }; + + /* + ** no job, resume normal processing + */ + if (DEBUG_FLAGS & DEBUG_RESTART) printf (" -- remove trap\n"); + np->script->start0[0] = SCR_INT ^ IFFALSE (0); + break; + + case SIR_SENSE_FAILED: + /*------------------------------------------- + ** While trying to select for + ** getting the condition code, + ** a target reselected us. + **------------------------------------------- + */ + if (DEBUG_FLAGS & DEBUG_RESTART) { + PRINT_ADDR(cp->cmd); + printf ("in getcc reselect by t%d.\n", + (int)INB(nc_ssid) & 0x0f); + } + + /* + ** Mark this job + */ + cp->host_status = HS_BUSY; + cp->scsi_status = S_CHECK_COND; + np->target[cp->cmd->target].hold_cp = cp; + + /* + ** And patch code to restart it. + */ + np->script->start0[0] = SCR_INT; + break; + +/*----------------------------------------------------------------------------- +** +** Was Sie schon immer ueber transfermode negotiation wissen wollten ... +** +** We try to negotiate sync and wide transfer only after +** a successfull inquire command. We look at byte 7 of the +** inquire data to determine the capabilities of the target. +** +** When we try to negotiate, we append the negotiation message +** to the identify and (maybe) simple tag message. +** The host status field is set to HS_NEGOTIATE to mark this +** situation. +** +** If the target doesn't answer this message immidiately +** (as required by the standard), the SIR_NEGO_FAIL interrupt +** will be raised eventually. +** The handler removes the HS_NEGOTIATE status, and sets the +** negotiated value to the default (async / nowide). +** +** If we receive a matching answer immediately, we check it +** for validity, and set the values. +** +** If we receive a Reject message immediately, we assume the +** negotiation has failed, and fall back to standard values. +** +** If we receive a negotiation message while not in HS_NEGOTIATE +** state, it's a target initiated negotiation. We prepare a +** (hopefully) valid answer, set our parameters, and send back +** this answer to the target. +** +** If the target doesn't fetch the answer (no message out phase), +** we assume the negotiation has failed, and fall back to default +** settings. +** +** When we set the values, we adjust them in all ccbs belonging +** to this target, in the controller's register, and in the "phys" +** field of the controller's struct ncb. +** +** Possible cases: hs sir msg_in value send goto +** We try try to negotiate: +** -> target doesnt't msgin NEG FAIL noop defa. - dispatch +** -> target rejected our msg NEG FAIL reject defa. - dispatch +** -> target answered (ok) NEG SYNC sdtr set - clrack +** -> target answered (!ok) NEG SYNC sdtr defa. REJ--->msg_bad +** -> target answered (ok) NEG WIDE wdtr set - clrack +** -> target answered (!ok) NEG WIDE wdtr defa. REJ--->msg_bad +** -> any other msgin NEG FAIL noop defa. - dispatch +** +** Target tries to negotiate: +** -> incoming message --- SYNC sdtr set SDTR - +** -> incoming message --- WIDE wdtr set WDTR - +** We sent our answer: +** -> target doesn't msgout --- PROTO ? defa. - dispatch +** +**----------------------------------------------------------------------------- +*/ + + case SIR_NEGO_FAILED: + /*------------------------------------------------------- + ** + ** Negotiation failed. + ** Target doesn't send an answer message, + ** or target rejected our message. + ** + ** Remove negotiation request. + ** + **------------------------------------------------------- + */ + OUTB (HS_PRT, HS_BUSY); + + /* fall through */ + + case SIR_NEGO_PROTO: + /*------------------------------------------------------- + ** + ** Negotiation failed. + ** Target doesn't fetch the answer message. + ** + **------------------------------------------------------- + */ + + if (DEBUG_FLAGS & DEBUG_NEGO) { + PRINT_ADDR(cp->cmd); + printf ("negotiation failed sir=%x status=%x.\n", + num, cp->nego_status); + }; + + /* + ** any error in negotiation: + ** fall back to default mode. + */ + switch (cp->nego_status) { + + case NS_SYNC: + ncr_setsync (np, cp, 0xe0); + break; + + case NS_WIDE: + ncr_setwide (np, cp, 0); + break; + + }; + np->msgin [0] = M_NOOP; + np->msgout[0] = M_NOOP; + cp->nego_status = 0; + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch)); + break; + + case SIR_NEGO_SYNC: + /* + ** Synchronous request message received. + */ + + if (DEBUG_FLAGS & DEBUG_NEGO) { + PRINT_ADDR(cp->cmd); + printf ("sync msgin: "); + (void) ncr_show_msg (np->msgin); + printf (".\n"); + }; + + /* + ** get requested values. + */ + + chg = 0; + per = np->msgin[3]; + ofs = np->msgin[4]; + if (ofs==0) per=255; + + /* + ** if target sends SDTR message, + ** it CAN transfer synch. + */ + + if (ofs) + tp->inqdata[7] |= INQ7_SYNC; + + /* + ** check values against driver limits. + */ + + if (per < np->ns_sync) + {chg = 1; per = np->ns_sync;} + if (per < tp->minsync) + {chg = 1; per = tp->minsync;} + if (ofs > tp->maxoffs) + {chg = 1; ofs = tp->maxoffs;} + + /* + ** Check against controller limits. + */ + fak = (4ul * per - 1) / np->ns_sync - 3; + if (ofs && (fak>7)) {chg = 1; ofs = 0;} + if (!ofs) fak=7; + + if (DEBUG_FLAGS & DEBUG_NEGO) { + PRINT_ADDR(cp->cmd); + printf ("sync: per=%d ofs=%d fak=%d chg=%d.\n", + per, ofs, fak, chg); + } + + if (INB (HS_PRT) == HS_NEGOTIATE) { + OUTB (HS_PRT, HS_BUSY); + switch (cp->nego_status) { + + case NS_SYNC: + /* + ** This was an answer message + */ + if (chg) { + /* + ** Answer wasn't acceptable. + */ + ncr_setsync (np, cp, 0xe0); + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad)); + } else { + /* + ** Answer is ok. + */ + ncr_setsync (np, cp, (fak<<5)|ofs); + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack)); + }; + return; + + case NS_WIDE: + ncr_setwide (np, cp, 0); + break; + }; + }; + + /* + ** It was a request. + ** Check against the table of target capabilities. + ** If target not capable force M_REJECT and asynchronous. + */ + if (np->unit < SCSI_NCR_MAX_HOST) { + tp->inqdata[7] &= + (target_capabilities[np->unit].and_map[target]); + if (!(tp->inqdata[7] & INQ7_SYNC)) { + ofs = 0; + fak = 7; + } + } + + /* + ** It was a request. Set value and + ** prepare an answer message + */ + + ncr_setsync (np, cp, (fak<<5)|ofs); + + np->msgout[0] = M_EXTENDED; + np->msgout[1] = 3; + np->msgout[2] = M_X_SYNC_REQ; + np->msgout[3] = per; + np->msgout[4] = ofs; + + cp->nego_status = NS_SYNC; + + if (DEBUG_FLAGS & DEBUG_NEGO) { + PRINT_ADDR(cp->cmd); + printf ("sync msgout: "); + (void) ncr_show_msg (np->msgin); + printf (".\n"); + } + + if (!ofs) { + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad)); + return; + } + np->msgin [0] = M_NOOP; + + break; + + case SIR_NEGO_WIDE: + /* + ** Wide request message received. + */ + if (DEBUG_FLAGS & DEBUG_NEGO) { + PRINT_ADDR(cp->cmd); + printf ("wide msgin: "); + (void) ncr_show_msg (np->msgin); + printf (".\n"); + }; + + /* + ** get requested values. + */ + + chg = 0; + wide = np->msgin[3]; + + /* + ** if target sends WDTR message, + ** it CAN transfer wide. + */ + + if (wide) + tp->inqdata[7] |= INQ7_WIDE16; + + /* + ** check values against driver limits. + */ + + if (wide > tp->usrwide) + {chg = 1; wide = tp->usrwide;} + + if (DEBUG_FLAGS & DEBUG_NEGO) { + PRINT_ADDR(cp->cmd); + printf ("wide: wide=%d chg=%d.\n", wide, chg); + } + + if (INB (HS_PRT) == HS_NEGOTIATE) { + OUTB (HS_PRT, HS_BUSY); + switch (cp->nego_status) { + + case NS_WIDE: + /* + ** This was an answer message + */ + if (chg) { + /* + ** Answer wasn't acceptable. + */ + ncr_setwide (np, cp, 0); + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad)); + } else { + /* + ** Answer is ok. + */ + ncr_setwide (np, cp, wide); + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack)); + }; + return; + + case NS_SYNC: + ncr_setsync (np, cp, 0xe0); + break; + }; + }; + + /* + ** It was a request, set value and + ** prepare an answer message + */ + + ncr_setwide (np, cp, wide); + + np->msgout[0] = M_EXTENDED; + np->msgout[1] = 2; + np->msgout[2] = M_X_WIDE_REQ; + np->msgout[3] = wide; + + np->msgin [0] = M_NOOP; + + cp->nego_status = NS_WIDE; + + if (DEBUG_FLAGS & DEBUG_NEGO) { + PRINT_ADDR(cp->cmd); + printf ("wide msgout: "); + (void) ncr_show_msg (np->msgin); + printf (".\n"); + } + break; + +/*-------------------------------------------------------------------- +** +** Processing of special messages +** +**-------------------------------------------------------------------- +*/ + + case SIR_REJECT_RECEIVED: + /*----------------------------------------------- + ** + ** We received a M_REJECT message. + ** + **----------------------------------------------- + */ + + PRINT_ADDR(cp->cmd); + printf ("M_REJECT received (%x:%x).\n", + (unsigned)np->lastmsg, np->msgout[0]); + break; + + case SIR_REJECT_SENT: + /*----------------------------------------------- + ** + ** We received an unknown message + ** + **----------------------------------------------- + */ + + PRINT_ADDR(cp->cmd); + printf ("M_REJECT sent for "); + (void) ncr_show_msg (np->msgin); + printf (".\n"); + break; + +/*-------------------------------------------------------------------- +** +** Processing of special messages +** +**-------------------------------------------------------------------- +*/ + + case SIR_IGN_RESIDUE: + /*----------------------------------------------- + ** + ** We received an IGNORE RESIDUE message, + ** which couldn't be handled by the script. + ** + **----------------------------------------------- + */ + + PRINT_ADDR(cp->cmd); + printf ("M_IGN_RESIDUE received, but not yet implemented.\n"); + break; + + case SIR_MISSING_SAVE: + /*----------------------------------------------- + ** + ** We received an DISCONNECT message, + ** but the datapointer wasn't saved before. + ** + **----------------------------------------------- + */ + + PRINT_ADDR(cp->cmd); + printf ("M_DISCONNECT received, but datapointer not saved:\n" + "\tdata=%x save=%x goal=%x.\n", + (unsigned) INL (nc_temp), + (unsigned) np->header.savep, + (unsigned) np->header.goalp); + break; + +/*-------------------------------------------------------------------- +** +** Processing of a "S_QUEUE_FULL" status. +** +** The current command has been rejected, +** because there are too many in the command queue. +** We have started too many commands for that target. +** +** If possible, reinsert at head of queue. +** Stall queue until there are no disconnected jobs +** (ncr is REALLY idle). Then restart processing. +** +** We should restart the current job after the controller +** has become idle. But this is not yet implemented. +** +**-------------------------------------------------------------------- +*/ + case SIR_STALL_QUEUE: + /*----------------------------------------------- + ** + ** Stall the start queue. + ** + **----------------------------------------------- + */ + PRINT_ADDR(cp->cmd); + printf ("queue full.\n"); + + np->script->start1[0] = SCR_INT; + + /* + ** For the moment tagged transfers cannot be disabled. + */ +#if 0 + /* + ** Try to disable tagged transfers. + */ + ncr_setmaxtags (np, &np->target[target], 0); +#endif + + /* + ** @QUEUE@ + ** + ** Should update the launch field of the + ** current job to be able to restart it. + ** Then prepend it to the start queue. + */ + + /* fall through */ + + case SIR_STALL_RESTART: + /*----------------------------------------------- + ** + ** Enable selecting again, + ** if NO disconnected jobs. + ** + **----------------------------------------------- + */ + /* + ** Look for a disconnected job. + */ + cp = &np->ccb; + while (cp && cp->host_status != HS_DISCONNECT) + cp = cp->link_ccb; + + /* + ** if there is one, ... + */ + if (cp) { + /* + ** wait for reselection + */ + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, reselect)); + return; + }; + + /* + ** else remove the interrupt. + */ + + printf ("%s: queue empty.\n", ncr_name (np)); + np->script->start1[0] = SCR_INT ^ IFFALSE (0); + break; + }; + +out: + OUTB (nc_dcntl, (STD|NOCOM)); +} + +/*========================================================== +** +** +** Aquire a control block +** +** +**========================================================== +*/ + +static ccb_p ncr_get_ccb + (ncb_p np, u_long target, u_long lun) +{ + lcb_p lp; + ccb_p cp = (ccb_p) 0; + + /* + ** Lun structure available ? + */ + + lp = np->target[target].lp[lun]; + if (lp) { + cp = lp->next_ccb; + + /* + ** Look for free CCB + */ + + while (cp && cp->magic) cp = cp->next_ccb; + } + + /* + ** if nothing available, take the default. + ** DANGEROUS, because this ccb is not suitable for + ** reselection. + ** If lp->actccbs > 0 wait for a suitable ccb to be free. + */ + if ((!cp) && lp && lp->actccbs > 0) + return ((ccb_p) 0); + + if (!cp) cp = &np->ccb; + + /* + ** Wait until available. + */ +#if 0 + while (cp->magic) { + if (flags & SCSI_NOSLEEP) break; + if (tsleep ((caddr_t)cp, PRIBIO|PCATCH, "ncr", 0)) + break; + }; +#endif + + if (cp->magic) + return ((ccb_p) 0); + + cp->magic = 1; + return (cp); +} + +/*========================================================== +** +** +** Release one control block +** +** +**========================================================== +*/ + +void ncr_free_ccb (ncb_p np, ccb_p cp) +{ + /* + ** sanity + */ + + assert (cp != NULL); + + cp -> host_status = HS_IDLE; + cp -> magic = 0; +#if 0 + if (cp == &np->ccb) + wakeup ((caddr_t) cp); +#endif +} + +/*========================================================== +** +** +** Allocation of resources for Targets/Luns/Tags. +** +** +**========================================================== +*/ + +static void ncr_alloc_ccb (ncb_p np, u_long target, u_long lun) +{ + tcb_p tp; + lcb_p lp; + ccb_p cp; + + assert (np != NULL); + + if (target>=MAX_TARGET) return; + if (lun >=MAX_LUN ) return; + + tp=&np->target[target]; + + if (!tp->jump_tcb.l_cmd) { + + /* + ** initialize it. + */ + tp->jump_tcb.l_cmd = (SCR_JUMP^IFFALSE (DATA (0x80 + target))); + tp->jump_tcb.l_paddr = np->jump_tcb.l_paddr; + + tp->getscr[0] = SCR_COPY (1); + tp->getscr[1] = vtophys (&tp->sval); + tp->getscr[2] = np->paddr + offsetof (struct ncr_reg, nc_sxfer); + tp->getscr[3] = SCR_COPY (1); + tp->getscr[4] = vtophys (&tp->wval); + tp->getscr[5] = np->paddr + offsetof (struct ncr_reg, nc_scntl3); + + assert (( (offsetof(struct ncr_reg, nc_sxfer) ^ + offsetof(struct tcb , sval )) &3) == 0); + assert (( (offsetof(struct ncr_reg, nc_scntl3) ^ + offsetof(struct tcb , wval )) &3) == 0); + + tp->call_lun.l_cmd = (SCR_CALL); + tp->call_lun.l_paddr = NCB_SCRIPT_PHYS (np, resel_lun); + + tp->jump_lcb.l_cmd = (SCR_JUMP); + tp->jump_lcb.l_paddr = NCB_SCRIPT_PHYS (np, abort); + np->jump_tcb.l_paddr = vtophys (&tp->jump_tcb); + } + + /* + ** Logic unit control block + */ + lp = tp->lp[lun]; + if (!lp) { + /* + ** Allocate a lcb + */ + lp = (lcb_p) m_alloc (sizeof (struct lcb)); + if (!lp) return; + + if (DEBUG_FLAGS & DEBUG_ALLOC) { + PRINT_LUN(np, target, lun); + printf ("new lcb @%p.\n", lp); + } + + /* + ** Initialize it + */ + bzero (lp, sizeof (*lp)); + lp->jump_lcb.l_cmd = (SCR_JUMP ^ IFFALSE (DATA (lun))); + lp->jump_lcb.l_paddr = tp->jump_lcb.l_paddr; + + lp->call_tag.l_cmd = (SCR_CALL); + lp->call_tag.l_paddr = NCB_SCRIPT_PHYS (np, resel_tag); + + lp->jump_ccb.l_cmd = (SCR_JUMP); + lp->jump_ccb.l_paddr = NCB_SCRIPT_PHYS (np, aborttag); + + lp->actlink = 1; + + /* + ** Chain into LUN list + */ + tp->jump_lcb.l_paddr = vtophys (&lp->jump_lcb); + tp->lp[lun] = lp; + +#ifndef SCSI_NCR_TAGGED_QUEUE_DISABLED + if (!lp->usetags) { + ncr_setmaxtags (np, tp, SCSI_NCR_MAX_TAGS); + } +#endif + } + + /* + ** Allocate ccbs up to lp->reqccbs. + ** + ** This modification will be reworked in a future release. + */ + +loop_alloc_ccb: + + /* + ** Limit possible number of ccbs. + ** + ** If tagged command queueing is enabled, + ** can use more than one ccb. + */ + if (np->actccbs >= MAX_START-2) return; + if (lp->actccbs && (lp->actccbs >= lp->reqccbs)) + return; + + /* + ** Allocate a ccb + */ + cp = (ccb_p) m_alloc (sizeof (struct ccb)); + if (!cp) + return; + + if (DEBUG_FLAGS & DEBUG_ALLOC) { + PRINT_LUN(np, target, lun); + printf ("new ccb @%p.\n", cp); + } + + /* + ** Count it + */ + lp->actccbs++; + np->actccbs++; + + /* + ** Initialize it + */ + bzero (cp, sizeof (*cp)); + + /* + ** Fill in physical addresses + */ + + cp->p_ccb = vtophys (cp); + + /* + ** Chain into reselect list + */ + cp->jump_ccb.l_cmd = SCR_JUMP; + cp->jump_ccb.l_paddr = lp->jump_ccb.l_paddr; + lp->jump_ccb.l_paddr = CCB_PHYS (cp, jump_ccb); + cp->call_tmp.l_cmd = SCR_CALL; + cp->call_tmp.l_paddr = NCB_SCRIPT_PHYS (np, resel_tmp); + + /* + ** Chain into wakeup list + */ + cp->link_ccb = np->ccb.link_ccb; + np->ccb.link_ccb = cp; + + /* + ** Chain into CCB list + */ + cp->next_ccb = lp->next_ccb; + lp->next_ccb = cp; + +goto loop_alloc_ccb; +} + +/*========================================================== +** +** +** Build Scatter Gather Block +** +** +**========================================================== +** +** The transfer area may be scattered among +** several non adjacent physical pages. +** +** We may use MAX_SCATTER blocks. +** +**---------------------------------------------------------- +*/ + +/* FreeBSD driver important comments +** --------------------------------- +** We try to reduce the number of interrupts caused +** by unexpected phase changes due to disconnects. +** A typical harddisk may disconnect before ANY block. +** If we wanted to avoid unexpected phase changes at all +** we had to use a break point every 512 bytes. +** Of course the number of scatter/gather blocks is +** limited. +*/ + +/* +** The scatterlist passed by the linux middle-level scsi drivers +** may contain blocks of any size (Generaly < 1024 bytes blocks, +** can be 4096 with a 4K fs). +*/ + +#if defined(SCSI_NCR_SEGMENT_SIZE) +static int ncr_scatter(ccb_p cp, Scsi_Cmnd *cmd) +{ + struct scatterlist *scatter; + struct dsb *phys; + register u_short segment = 0; + register u_short o_segment = 0; + u_short chunk, chunk_min; + u_long segaddr; + int segsize; + int datalen; + + phys = &cp->phys; + cp->data_len = 0; + + /* + ** Compute a good value for chunk size + ** If SCSI_NCR_SEGMENT_SIZE is OK, we will try to use it. + */ + + if (!cmd->use_sg) + cp->data_len = cmd->request_bufflen; + else { + scatter = (struct scatterlist *)cmd->buffer; + for (segment = 0 ; segment < cmd->use_sg ; segment++) + cp->data_len += scatter[segment].length; + } + + + if (!cp->data_len) { + bzero (&phys->data, sizeof (phys->data)); + return 0; + } + + chunk_min = cp->data_len / MAX_SCATTER; + for (chunk = SCSI_NCR_SEGMENT_SIZE ; chunk < chunk_min ; chunk += chunk); + + /* + ** If the linux scsi command is not a scatterlist, + ** the computed chunk size is OK. + */ + + if (!cmd->use_sg) { + bzero (&phys->data, sizeof (phys->data)); + datalen = cmd->request_bufflen; + segaddr = vtophys(cmd->request_buffer); + segsize = chunk; + o_segment = 0; + +if (DEBUG_FLAGS & DEBUG_SCATTER) + printf("ncr53c8xx: re-scattering physical=0x%x size=%d chunk=%d.\n", + (unsigned) segaddr, (int) datalen, (int) chunk); + + while (datalen && (o_segment < MAX_SCATTER)) { + if (segsize > datalen) segsize = datalen; + phys->data[o_segment].addr = segaddr; + phys->data[o_segment].size = segsize; + + datalen -= segsize; + +if(DEBUG_FLAGS & DEBUG_SCATTER) + printf ("ncr53c8xx: seg #%d addr=%lx size=%d (rest=%d).\n", + o_segment, segaddr, (int) segsize, (int) datalen); + + segaddr += segsize; + o_segment++; + } + + return datalen ? -1 : o_segment; + } + + /* + ** Else, the computed chunk size is not so good + ** and we have to iterate. + ** Rescatter the Linux scatterlist into the data block descriptor. + ** Loop if necessary, beginning with the not so good chunk size and + ** doubling it if the scatter process fails. + */ + + scatter = (struct scatterlist *)cmd->buffer; + for (segment = 0; segment < cmd->use_sg; chunk += chunk) { + o_segment = 0; + bzero (&phys->data, sizeof (phys->data)); + for (segment = 0 ; segment < cmd->use_sg ; segment++) { + datalen = scatter[segment].length; + segaddr = vtophys(scatter[segment].address); + segsize = chunk; + +if (DEBUG_FLAGS & DEBUG_SCATTER) + printf("ncr53c8xx: re-scattering physical=0x%x size=%d chunk=%d.\n", + (unsigned) segaddr, (int) datalen, (int) chunk); + + while (datalen && (o_segment < MAX_SCATTER)) { + if (segsize > datalen) segsize = datalen; + phys->data[o_segment].addr = segaddr; + phys->data[o_segment].size = segsize; + + datalen -= segsize; + +if(DEBUG_FLAGS & DEBUG_SCATTER) + printf ("ncr53c8xx: seg #%d addr=%lx size=%d (rest=%d).\n", + o_segment, segaddr, (int) segsize, (int) datalen); + + segaddr += segsize; + o_segment++; + } + + if (datalen) break; + } + } + + return segment < cmd->use_sg ? -1 : o_segment; +} + +#else /* !defined SCSI_NCR_SEGMENT_SIZE */ + +static int ncr_scatter(ccb_p cp, Scsi_Cmnd *cmd) +{ + struct dsb *phys = &cp->phys; + u_short segment = 0; + + cp->data_len = 0; + bzero (&phys->data, sizeof (phys->data)); + + if (!cmd->use_sg) { + phys->data[segment].addr = vtophys(cmd->request_buffer); + phys->data[segment].size = cmd->request_bufflen; + cp->data_len += phys->data[segment].size; + segment++; + return segment; + } + + while (segment < cmd->use_sg && segment < MAX_SCATTER) { + struct scatterlist *scatter = (struct scatterlist *)cmd->buffer; + + phys->data[segment].addr = vtophys(scatter[segment].address); + phys->data[segment].size = scatter[segment].length; + cp->data_len += phys->data[segment].size; + ++segment; + } + + return segment < cmd->use_sg ? -1 : segment; +} +#endif /* SCSI_NCR_SEGMENT_SIZE */ + +/*========================================================== +** +** +** Test the pci bus snoop logic :-( +** +** Has to be called with interrupts disabled. +** +** +**========================================================== +*/ + +#ifndef NCR_IOMAPPED +static int ncr_regtest (struct ncb* np) +{ + register volatile u_long data; + /* + ** ncr registers may NOT be cached. + ** write 0xffffffff to a read only register area, + ** and try to read it back. + */ + data = 0xffffffff; + OUTL_OFF(offsetof(struct ncr_reg, nc_dstat), data); + data = INL_OFF(offsetof(struct ncr_reg, nc_dstat)); +#if 1 + if (data == 0xffffffff) { +#else + if ((data & 0xe2f0fffd) != 0x02000080) { +#endif + printf ("CACHE TEST FAILED: reg dstat-sstat2 readback %x.\n", + (unsigned) data); + return (0x10); + }; + return (0); +} +#endif + +static int ncr_snooptest (struct ncb* np) +{ + u_long ncr_rd, ncr_wr, ncr_bk, host_rd, host_wr, pc, err=0; + int i; +#ifndef NCR_IOMAPPED + if (np->use_mmio) { + err |= ncr_regtest (np); + if (err) return (err); + } +#endif + /* + ** init + */ + pc = NCB_SCRIPT_PHYS (np, snooptest); + host_wr = 1; + ncr_wr = 2; + /* + ** Set memory and register. + */ + np->ncr_cache = host_wr; + OUTL (nc_temp, ncr_wr); + /* + ** Start script (exchange values) + */ + OUTL (nc_dsp, pc); + /* + ** Wait 'til done (with timeout) + */ + for (i=0; incr_cache; + ncr_rd = INL (nc_scratcha); + ncr_bk = INL (nc_temp); + /* + ** Reset ncr chip + */ + OUTB (nc_istat, SRST); + DELAY (1000); + OUTB (nc_istat, 0 ); + /* + ** check for timeout + */ + if (i>=NCR_SNOOP_TIMEOUT) { + printf ("CACHE TEST FAILED: timeout.\n"); + return (0x20); + }; + /* + ** Check termination position. + */ + if (pc != NCB_SCRIPT_PHYS (np, snoopend)+8) { + printf ("CACHE TEST FAILED: script execution failed.\n"); + return (0x40); + }; + /* + ** Show results. + */ + if (host_wr != ncr_rd) { + printf ("CACHE TEST FAILED: host wrote %d, ncr read %d.\n", + (int) host_wr, (int) ncr_rd); + err |= 1; + }; + if (host_rd != ncr_wr) { + printf ("CACHE TEST FAILED: ncr wrote %d, host read %d.\n", + (int) ncr_wr, (int) host_rd); + err |= 2; + }; + if (ncr_bk != ncr_wr) { + printf ("CACHE TEST FAILED: ncr wrote %d, read back %d.\n", + (int) ncr_wr, (int) ncr_bk); + err |= 4; + }; + return (err); +} + +/*========================================================== +** +** +** Profiling the drivers and targets performance. +** +** +**========================================================== +*/ + +/* +** Compute the difference in milliseconds. +**/ + +#ifdef SCSI_NCR_PROFILE + +static int ncr_delta (u_long from, u_long to) +{ + if (!from) return (-1); + if (!to) return (-2); + return ((to - from) * 1000 / HZ ); +} + +#define PROFILE cp->phys.header.stamp +static void ncb_profile (ncb_p np, ccb_p cp) +{ + int co, da, st, en, di, se, post,work,disc; + u_long diff; + + PROFILE.end = jiffies; + + st = ncr_delta (PROFILE.start,PROFILE.status); + if (st<0) return; /* status not reached */ + + da = ncr_delta (PROFILE.start,PROFILE.data); + if (da<0) return; /* No data transfer phase */ + + co = ncr_delta (PROFILE.start,PROFILE.command); + if (co<0) return; /* command not executed */ + + en = ncr_delta (PROFILE.start,PROFILE.end), + di = ncr_delta (PROFILE.start,PROFILE.disconnect), + se = ncr_delta (PROFILE.start,PROFILE.select); + post = en - st; + + /* + ** @PROFILE@ Disconnect time invalid if multiple disconnects + */ + + if (di>=0) disc = se-di; else disc = 0; + + work = (st - co) - disc; + + diff = (np->disc_phys - np->disc_ref) & 0xff; + np->disc_ref += diff; + + np->profile.num_trans += 1; + if (cp->cmd) { + np->profile.num_kbytes += (cp->cmd->request_bufflen >> 10); + np->profile.rest_bytes += (cp->cmd->request_bufflen & (0x400-1)); + if (np->profile.rest_bytes >= 0x400) { + ++np->profile.num_kbytes; + np->profile.rest_bytes -= 0x400; + } + } + np->profile.num_disc += diff; + np->profile.ms_setup += co; + np->profile.ms_data += work; + np->profile.ms_disc += disc; + np->profile.ms_post += post; +} +#undef PROFILE + +#endif /* SCSI_NCR_PROFILE */ + +/*========================================================== +** +** +** Device lookup. +** +** @GENSCSI@ should be integrated to scsiconf.c +** +** +**========================================================== +*/ + +struct table_entry { + char * manufacturer; + char * model; + char * version; + u_long info; +}; + +static struct table_entry device_tab[] = +{ +#ifdef NCR_GETCC_WITHMSG + {"", "", "", QUIRK_NOMSG}, + {"SONY", "SDT-5000", "3.17", QUIRK_NOMSG}, + {"WangDAT", "Model 2600", "01.7", QUIRK_NOMSG}, + {"WangDAT", "Model 3200", "02.2", QUIRK_NOMSG}, + {"WangDAT", "Model 1300", "02.4", QUIRK_NOMSG}, +#endif + {"", "", "", 0} /* catch all: must be last entry. */ +}; + +static u_long ncr_lookup(char * id) +{ + struct table_entry * p = device_tab; + char *d, *r, c; + + for (;;p++) { + + d = id+8; + r = p->manufacturer; + while ((c=*r++)) if (c!=*d++) break; + if (c) continue; + + d = id+16; + r = p->model; + while ((c=*r++)) if (c!=*d++) break; + if (c) continue; + + d = id+32; + r = p->version; + while ((c=*r++)) if (c!=*d++) break; + if (c) continue; + + return (p->info); + } +} + +/*========================================================== +** +** Determine the ncr's clock frequency. +** This is important for the negotiation +** of the synchronous transfer rate. +** +**========================================================== +** +** Note: we have to return the correct value. +** THERE IS NO SAVE DEFAULT VALUE. +** +** We assume that all NCR based boards are delivered +** with a 40Mhz clock. Because we have to divide +** by an integer value greater than 3, only clock +** frequencies of 40Mhz (/4) or 50MHz (/5) permit +** the FAST-SCSI rate of 10MHz. +** +**---------------------------------------------------------- +*/ + +#ifndef NCR_CLOCK +# define NCR_CLOCK 40 +#endif /* NCR_CLOCK */ + + +static void ncr_getclock (ncb_p np) +{ + u_char tbl[5] = {6,2,3,4,6}; + u_char f; + u_char ns_clock = (1000/NCR_CLOCK); + + /* + ** Compute the best value for scntl3. + */ + + f = (2 * MIN_SYNC_PD - 1) / ns_clock; + if (!f ) f=1; + if (f>4) f=4; + np -> ns_sync = (ns_clock * tbl[f]) / 2; + np -> rv_scntl3 = f<<4; + + f = (2 * MIN_ASYNC_PD - 1) / ns_clock; + if (!f ) f=1; + if (f>4) f=4; + np -> ns_async = (ns_clock * tbl[f]) / 2; + np -> rv_scntl3 |= f; + if (DEBUG_FLAGS & DEBUG_TIMING) + printf ("%s: sclk=%d async=%d sync=%d (ns) scntl3=0x%x\n", + ncr_name (np), ns_clock, np->ns_async, np->ns_sync, np->rv_scntl3); +} + +/*===================== LINUX ENTRY POINTS SECTION ==========================*/ + +#ifndef uchar +#define uchar unsigned char +#endif + +#ifndef ushort +#define ushort unsigned short +#endif + +#ifndef ulong +#define ulong unsigned long +#endif + +static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt, int unit, int board, int chip, + uchar bus, uchar device_fn, int options); + +/* +** NCR53C8XX devices description table +*/ + +static struct { + ushort pci_device_id; + int chip; + int max_revision; + int min_revision; +} pci_chip_ids[] = { + {PCI_DEVICE_ID_NCR_53C810, 810, -1, -1}, +/* {PCI_DEVICE_ID_NCR_53C810AP, 810, -1, -1}, */ + {PCI_DEVICE_ID_NCR_53C815, 815, -1, -1}, + {PCI_DEVICE_ID_NCR_53C820, 820, -1, -1}, + {PCI_DEVICE_ID_NCR_53C825, 825, -1, -1}, + {PCI_DEVICE_ID_NCR_53C860, 860, -1, -1}, + {PCI_DEVICE_ID_NCR_53C875, 875, -1, -1} +}; + +#define NPCI_CHIP_IDS (sizeof (pci_chip_ids) / sizeof(pci_chip_ids[0])) + +/* +** Linux entry point for NCR53C8XX devices detection routine. +** +** Called by the middle-level scsi drivers at initialization time, +** or at module installation. +** +** Read the PCI configuration and try to attach each +** detected NCR board. +** +** Returns the number of boards successfully attached. +*/ + +int ncr53c8xx_detect(Scsi_Host_Template *tpnt) +{ + int i; + int count = 0; /* Number of boards detected */ + uchar pci_bus, pci_device_fn; + short pci_index; /* Device index to PCI BIOS calls */ + +#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0) + tpnt->proc_dir = &proc_scsi_ncr53c8xx; +# ifdef SCSI_NCR_PROC_INFO_SUPPORT + tpnt->proc_info = ncr53c8xx_proc_info; +# endif +#endif + + if (pcibios_present()) { + for (i = 0; i < NPCI_CHIP_IDS; ++i) + for (pci_index = 0; + !pcibios_find_device(PCI_VENDOR_ID_NCR, + pci_chip_ids[i].pci_device_id, pci_index, &pci_bus, + &pci_device_fn); + ++pci_index) + if (!ncr53c8xx_pci_init(tpnt, count, 0, pci_chip_ids[i].chip, + pci_bus, pci_device_fn, /* no options */ 0)) + ++count; + } + + return count; +} + + +/* +** Read the PCI configuration of a found NCR board and +** try yo attach it. +*/ + +static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt, int unit, int board, int chip, + uchar bus, uchar device_fn, int options) +{ + ushort vendor_id, device_id, command; +#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0) + uint base, io_port; +#else + ulong base, io_port; +#endif + uchar irq, revision; + int error, expected_chip; + int expected_id = -1, max_revision = -1, min_revision = -1; + int i; + + printk("ncr53c8xx : at PCI bus %d, device %d, function %d\n", + bus, (int) (device_fn & 0xf8) >> 3, (int) device_fn & 7); + + if (!pcibios_present()) { + printk("ncr53c8xx : not initializing due to lack of PCI BIOS,\n"); + return -1; + } + + if ((error = pcibios_read_config_word( bus, device_fn, PCI_VENDOR_ID, &vendor_id)) || + (error = pcibios_read_config_word( bus, device_fn, PCI_DEVICE_ID, &device_id)) || + (error = pcibios_read_config_word( bus, device_fn, PCI_COMMAND, &command)) || + (error = pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0, &io_port)) || + (error = pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_1, &base)) || + (error = pcibios_read_config_byte (bus, device_fn, PCI_CLASS_REVISION, &revision)) || + (error = pcibios_read_config_byte (bus, device_fn, PCI_INTERRUPT_LINE, &irq))) { + printk("ncr53c8xx : error %s not initializing due to error reading configuration space\n", + pcibios_strerror(error)); + return -1; + } + + if (vendor_id != PCI_VENDOR_ID_NCR) { + printk("ncr53c8xx : not initializing, 0x%04x is not NCR vendor ID\n", (int) vendor_id); + return -1; + } + + + if (command & PCI_COMMAND_IO) { + if ((io_port & 3) != 1) { + printk("ncr53c8xx : disabling I/O mapping since base address 0 (0x%x)\n" + " bits 0..1 indicate a non-IO mapping\n", (int) io_port); + io_port = 0; + } + else + io_port &= PCI_BASE_ADDRESS_IO_MASK; + } + else + io_port = 0; + + if (command & PCI_COMMAND_MEMORY) { + if ((base & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) { + printk("ncr53c8xx : disabling memory mapping since base address 1\n" + " contains a non-memory mapping\n"); + base = 0; + } + else + base &= PCI_BASE_ADDRESS_MEM_MASK; + } + else + base = 0; + + if (!io_port && !base) { + printk("ncr53c8xx : not initializing, both I/O and memory mappings disabled\n"); + return -1; + } + + if (!(command & PCI_COMMAND_MASTER)) { + printk ("ncr53c8xx : not initializing, BUS MASTERING was disabled\n"); + return -1; + } + + for (i = 0; i < NPCI_CHIP_IDS; ++i) { + if (device_id == pci_chip_ids[i].pci_device_id) { + max_revision = pci_chip_ids[i].max_revision; + min_revision = pci_chip_ids[i].min_revision; + expected_chip = pci_chip_ids[i].chip; + } + if (chip == pci_chip_ids[i].chip) + expected_id = pci_chip_ids[i].pci_device_id; + } + + if (chip && device_id != expected_id) + printk("ncr53c8xx : warning : device id of 0x%04x doesn't\n" + " match expected 0x%04x\n", + (unsigned int) device_id, (unsigned int) expected_id ); + + if (max_revision != -1 && revision > max_revision) + printk("ncr53c8xx : warning : revision %d is greater than expected.\n", + (int) revision); + else if (min_revision != -1 && revision < min_revision) + printk("ncr53c8xx : warning : revision %d is lower than expected.\n", + (int) revision); + + if (io_port && check_region (io_port, 128)) { + printk("ncr53c8xx : IO region 0x%x to 0x%x is in use\n", + (int) io_port, (int) (io_port + 127)); + return -1; + } + + return ncr_attach (tpnt, unit, device_id, revision, chip, base, io_port, + (int) irq, bus, (uchar) device_fn); +} + +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,0,0) +/* +** Linux select queue depths function +*/ +static void ncr53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_device *devlist) +{ + struct scsi_device *device; + + for (device = devlist; device; device = device->next) { + if (device->host == host) { + if (device->tagged_supported) { + device->queue_depth = SCSI_NCR_MAX_TAGS; + } + else { + device->queue_depth = 1; + } +#ifdef DEBUG +printk("ncr53c8xx_select_queue_depth: id=%d, lun=%d, queue_depth=%d\n", + device->id, device->lun, device->queue_depth); +#endif + } + } +} +#endif + +/* +** Linux entry point of queuecommand() function +*/ + +int ncr53c8xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) +{ + int sts; +#ifdef DEBUG +printk("ncr53c8xx_queue_command\n"); +#endif + + if ((sts = ncr_queue_command(cmd, done)) != DID_OK) { + cmd->result = ScsiResult(sts, 0); + done(cmd); +#ifdef DEBUG +printk("ncr53c8xx : command not queued - result=%d\n", sts); +#endif + return sts; + } +#ifdef DEBUG +printk("ncr53c8xx : command successfully queued\n"); +#endif + return sts; +} + +/* +** Linux entry point of the interrupt handler +*/ + +#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70) +static void ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs) +#else +static void ncr53c8xx_intr(int irq, struct pt_regs * regs) +#endif +{ + struct Scsi_Host *host; + struct host_data *host_data; + +#ifdef DEBUG +printk("ncr53c8xx : interrupt received\n"); +#endif + + for (host = first_host; host; host = host->next) { + if (host->hostt == the_template && host->irq == irq) { + host_data = (struct host_data *) host->hostdata; +#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70) +# ifdef SCSI_NCR_SHARE_IRQ + if (dev_id == &host_data->ncb_data) + ncr_intr(&host_data->ncb_data); +# endif +#endif + ncr_intr(&host_data->ncb_data); + } + } +} + +/* +** Linux entry point of the timer handler +*/ + +static void ncr53c8xx_timeout(unsigned long np) +{ + ncr_timeout((ncb_p) np); +} + +/* +** Linux entry point of reset() function +*/ + +#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,98) +int ncr53c8xx_reset(Scsi_Cmnd *cmd, unsigned int reset_flags) +#else +int ncr53c8xx_reset(Scsi_Cmnd *cmd) +#endif +{ +#ifdef DEBUG +printk("ncr53c8xx_reset : reset call\n"); +#endif + return ncr_reset_bus(cmd); +} + +/* +** Linux entry point of abort() function +*/ + +int ncr53c8xx_abort(Scsi_Cmnd *cmd) +{ +printk("ncr53c8xx_abort : abort call\n"); + return ncr_abort_command(cmd); +} + +#ifdef MODULE +int ncr53c8xx_release(struct Scsi_Host *host) +{ + struct host_data *host_data; +#ifdef DEBUG +printk("ncr53c8xx : release\n"); +#endif + + for (host = first_host; host; host = host->next) { + if (host->hostt == the_template) { + host_data = (struct host_data *) host->hostdata; + ncr_detach(&host_data->ncb_data, host->irq); + } + } + + return 1; +} +#endif + + +/* +** Scsi command waiting list management. +** +** It may happen that we cannot insert a scsi command into the start queue, +** in the following circumstances. +** Too few preallocated ccb(s), +** maxtags < cmd_per_lun of the Linux host control block, +** etc... +** Such scsi commands are inserted into a waiting list. +** When a scsi command complete, we try to requeue the commands of the +** waiting list. +*/ + +#define next_wcmd host_scribble + +static void insert_into_waiting_list(ncb_p np, Scsi_Cmnd *cmd) +{ + Scsi_Cmnd *wcmd; + +#ifdef DEBUG_WAITING_LIST + printf("%s: cmd %lx inserted into waiting list\n", ncr_name(np), (u_long) cmd); +#endif + cmd->next_wcmd = 0; + if (!(wcmd = np->waiting_list)) np->waiting_list = cmd; + else { + while ((wcmd->next_wcmd) != 0) + wcmd = (Scsi_Cmnd *) wcmd->next_wcmd; + wcmd->next_wcmd = (char *) cmd; + } +} + +static Scsi_Cmnd *remove_from_waiting_list(ncb_p np, Scsi_Cmnd *cmd) +{ + Scsi_Cmnd *wcmd; + + if (!(wcmd = np->waiting_list)) return 0; + while (wcmd->next_wcmd) { + if (cmd == (Scsi_Cmnd *) wcmd->next_wcmd) { + wcmd->next_wcmd = cmd->next_wcmd; + cmd->next_wcmd = 0; +#ifdef DEBUG_WAITING_LIST + printf("%s: cmd %lx removed from waiting list\n", ncr_name(np), (u_long) cmd); +#endif + return cmd; + } + } + return 0; +} + +static void process_waiting_list(ncb_p np, int sts) +{ + Scsi_Cmnd *waiting_list, *wcmd; + + waiting_list = np->waiting_list; + np->waiting_list = 0; + +#ifdef DEBUG_WAITING_LIST + if (waiting_list) printf("%s: waiting_list=%lx processing sts=%d\n", ncr_name(np), (u_long) waiting_list, sts); +#endif + while ((wcmd = waiting_list) != 0) { + waiting_list = (Scsi_Cmnd *) wcmd->next_wcmd; + wcmd->next_wcmd = 0; + if (sts == DID_OK) { +#ifdef DEBUG_WAITING_LIST + printf("%s: cmd %lx trying to requeue\n", ncr_name(np), (u_long) wcmd); +#endif + sts = ncr_queue_command(wcmd, wcmd->scsi_done); + } + if (sts != DID_OK) { +#ifdef DEBUG_WAITING_LIST + printf("%s: cmd %lx done forced sts=%d\n", ncr_name(np), (u_long) wcmd, sts); +#endif + wcmd->result = ScsiResult(sts, 0); + wcmd->scsi_done(wcmd); + } + } +} + +#undef next_wcmd + +/* +** In order to patch the SCSI script for SAVE/RESTORE DATA POINTER, +** we need the direction of transfer. +** Linux middle-level scsi driver does not provide this information. +** So we have to guess it. +** My documentation about SCSI-II standard is old. Probably some opcode +** are missing. +** If I do'nt know the command code, I assume input transfer direction. +*/ + +static int guess_xfer_direction(int opcode) +{ + int d; + + switch(opcode) { + case 0x00: /* TEST UNIT READY 00 */ + case 0x08: /* READ(6) 08 */ + case 0x12: /* INQUIRY 12 */ + case 0x4D: /* LOG SENSE 4D */ + case 0x5A: /* MODE SENSE(10) 5A */ + case 0x1A: /* MODE SENSE(6) 1A */ + case 0x28: /* READ(10) 28 */ + case 0xA8: /* READ(12) A8 */ + case 0x3C: /* READ BUFFER 3C */ + case 0x1C: /* RECEIVE DIAGNOSTIC RESULTS 1C */ + case 0xB7: /* READ DEFECT DATA(12) B7 */ + case 0xB8: /* READ ELEMENT STATUS B8 */ + /* GET WINDOW 25 */ + case 0x25: /* READ CAPACITY 25 */ + case 0x29: /* READ GENERATION 29 */ + case 0x3E: /* READ LONG 3E */ + /* GET DATA BUFFER STATUS 34 */ + /* PRE-FETCH 34 */ + case 0x34: /* READ POSITION 34 */ + case 0x03: /* REQUEST SENSE 03 */ + case 0x05: /* READ BLOCK LIMITS 05 */ + case 0x0F: /* READ REVERSE 0F */ + case 0x14: /* RECOVER BUFFERED DATA 14 */ + case 0x2D: /* READ UPDATED BLOCK 2D */ + case 0x37: /* READ DEFECT DATA(10) 37 */ + case 0x42: /* READ SUB-CHANNEL 42 */ + case 0x43: /* READ TOC 43 */ + case 0x44: /* READ HEADER 44 */ + case 0xC7: /* ??? ??? C7 */ + d = XferIn; + break; + case 0x39: /* COMPARE 39 */ + case 0x3A: /* COPY AND VERIFY 3A */ + /* PRINT 0A */ + /* SEND MESSAGE(6) 0A */ + case 0x0A: /* WRITE(6) 0A */ + case 0x18: /* COPY 18 */ + case 0x4C: /* LOG SELECT 4C */ + case 0x55: /* MODE SELECT(10) 55 */ + case 0x3B: /* WRITE BUFFER 3B */ + case 0x1D: /* SEND DIAGNOSTIC 1D */ + case 0x40: /* CHANGE DEFINITION 40 */ + /* SEND MESSAGE(12) AA */ + case 0xAA: /* WRITE(12) AA */ + case 0xB6: /* SEND VOLUME TAG B6 */ + case 0x3F: /* WRITE LONG 3F */ + case 0x04: /* FORMAT UNIT 04 */ + /* INITIALIZE ELEMENT STATUS 07 */ + case 0x07: /* REASSIGN BLOCKS 07 */ + case 0x15: /* MODE SELECT(6) 15 */ + case 0x24: /* SET WINDOW 24 */ + case 0x2A: /* WRITE(10) 2A */ + case 0x2E: /* WRITE AND VERIFY(10) 2E */ + case 0xAE: /* WRITE AND VERIFY(12) AE */ + case 0xB0: /* SEARCH DATA HIGH(12) B0 */ + case 0xB1: /* SEARCH DATA EQUAL(12) B1 */ + case 0xB2: /* SEARCH DATA LOW(12) B2 */ + /* OBJECT POSITION 31 */ + case 0x30: /* SEARCH DATA HIGH(10) 30 */ + case 0x31: /* SEARCH DATA EQUAL(10) 31 */ + case 0x32: /* SEARCH DATA LOW(10) 32 */ + case 0x38: /* MEDIUM SCAN 38 */ + case 0x3D: /* UPDATE BLOCK 3D */ + case 0x41: /* WRITE SAME 41 */ + /* LOAD UNLOAD 1B */ + /* SCAN 1B */ + case 0x1B: /* START STOP UNIT 1B */ + d = XferOut; + break; + case 0x01: /* REZERO UNIT 01 */ + /* SEEK(6) 0B */ + case 0x0B: /* SLEW AND PRINT 0B */ + /* SYNCHRONIZE BUFFER 10 */ + case 0x10: /* WRITE FILEMARKS 10 */ + case 0x11: /* SPACE 11 */ + case 0x13: /* VERIFY 13 */ + case 0x16: /* RESERVE UNIT 16 */ + case 0x17: /* RELEASE UNIT 17 */ + case 0x19: /* ERASE 19 */ + /* LOCATE 2B */ + /* POSITION TO ELEMENT 2B */ + case 0x2B: /* SEEK(10) 2B */ + case 0x1E: /* PREVENT ALLOW MEDIUM REMOVAL 1E */ + case 0x2C: /* ERASE(10) 2C */ + case 0xAC: /* ERASE(12) AC */ + case 0x2F: /* VERIFY(10) 2F */ + case 0xAF: /* VERIFY(12) AF */ + case 0x33: /* SET LIMITS(10) 33 */ + case 0xB3: /* SET LIMITS(12) B3 */ + case 0x35: /* SYNCHRONIZE CACHE 35 */ + case 0x36: /* LOCK UNLOCK CACHE 36 */ + case 0x45: /* PLAY AUDIO(10) 45 */ + case 0x47: /* PLAY AUDIO MSF 47 */ + case 0x48: /* PLAY AUDIO TRACK/INDEX 48 */ + case 0x49: /* PLAY TRACK RELATIVE(10) 49 */ + case 0xA9: /* PLAY TRACK RELATIVE(12) A9 */ + case 0x4B: /* PAUSE/RESUME 4B */ + /* MOVE MEDIUM A5 */ + case 0xA5: /* PLAY AUDIO(12) A5 */ + case 0xA6: /* EXCHANGE MEDIUM A6 */ + case 0xB5: /* REQUEST VOLUME ELEMENT ADDRESS B5 */ + d = XferNone; + break; + default: + d = XferIn; + break; + } + + return d; +} + + +#ifdef SCSI_NCR_PROC_INFO_SUPPORT + +/*========================================================================= +** Proc file system stuff +** +** A read operation returns profile information. +** A write operation is a control command. +** The string is parsed in the driver code and the command is passed +** to the ncr_usercmd() function. +**========================================================================= +*/ + +#define is_digit(c) ((c) >= '0' && (c) <= '9') +#define digit_to_bin(c) ((c) - '0') +#define is_space(c) ((c) == ' ' || (c) == '\t') + +static int skip_spaces(char *ptr, int len) +{ + int cnt, c; + + for (cnt = len; cnt > 0 && (c = *ptr++) && is_space(c); cnt--); + + return (len - cnt); +} + +static int get_int_arg(char *ptr, int len, u_long *pv) +{ + int cnt, c; + u_long v; + + for (v = 0, cnt = len; cnt > 0 && (c = *ptr++) && is_digit(c); cnt--) { + v = (v * 10) + digit_to_bin(c); + } + + if (pv) + *pv = v; + + return (len - cnt); +} + +static int is_keyword(char *ptr, int len, char *verb) +{ + int verb_len = strlen(verb); + + if (len >= strlen(verb) && !memcmp(verb, ptr, verb_len)) + return verb_len; + else + return 0; + +} + +#define SKIP_SPACES(min_spaces) \ + if ((arg_len = skip_spaces(ptr, len)) < (min_spaces)) \ + return -EINVAL; \ + ptr += arg_len; len -= arg_len; + +#define GET_INT_ARG(v) \ + if (!(arg_len = get_int_arg(ptr, len, &(v)))) \ + return -EINVAL; \ + ptr += arg_len; len -= arg_len; + + +/* +** Parse a control command +*/ + +static int ncr_user_command(ncb_p np, char *buffer, int length) +{ + char *ptr = buffer; + int len = length; + struct usrcmd *uc = &np->user; + int arg_len; + u_long target; + + bzero(uc, sizeof(*uc)); + + if (len > 0 && ptr[len-1] == '\n') + --len; + + if ((arg_len = is_keyword(ptr, len, "setsync")) != 0) + uc->cmd = UC_SETSYNC; + else if ((arg_len = is_keyword(ptr, len, "settags")) != 0) + uc->cmd = UC_SETTAGS; + else if ((arg_len = is_keyword(ptr, len, "setorder")) != 0) + uc->cmd = UC_SETORDER; + else if ((arg_len = is_keyword(ptr, len, "setwide")) != 0) + uc->cmd = UC_SETWIDE; + else if ((arg_len = is_keyword(ptr, len, "setdebug")) != 0) + uc->cmd = UC_SETDEBUG; + else if ((arg_len = is_keyword(ptr, len, "setflag")) != 0) + uc->cmd = UC_SETFLAG; + else if ((arg_len = is_keyword(ptr, len, "clearprof")) != 0) + uc->cmd = UC_CLEARPROF; + else + arg_len = 0; + +#ifdef DEBUG_PROC_INFO +printf("ncr_user_command: arg_len=%d, cmd=%ld\n", arg_len, uc->cmd); +#endif + + if (!arg_len) + return -EINVAL; + ptr += arg_len; len -= arg_len; + + switch(uc->cmd) { + case UC_SETSYNC: + case UC_SETTAGS: + case UC_SETWIDE: + case UC_SETFLAG: + SKIP_SPACES(1); + GET_INT_ARG(target); +#ifdef DEBUG_PROC_INFO +printf("ncr_user_command: target=%ld\n", target); +#endif + if (target > MAX_TARGET) + return -EINVAL; + uc->target = (1<cmd) { + case UC_SETSYNC: + case UC_SETTAGS: + case UC_SETWIDE: + SKIP_SPACES(1); + GET_INT_ARG(uc->data); +#ifdef DEBUG_PROC_INFO +printf("ncr_user_command: data=%ld\n", uc->data); +#endif + break; + case UC_SETORDER: + SKIP_SPACES(1); + if ((arg_len = is_keyword(ptr, len, "simple"))) + uc->data = M_SIMPLE_TAG; + else if ((arg_len = is_keyword(ptr, len, "ordered"))) + uc->data = M_ORDERED_TAG; + else if ((arg_len = is_keyword(ptr, len, "default"))) + uc->data = 0; + else + return -EINVAL; + break; + case UC_SETDEBUG: + while (len > 0) { + SKIP_SPACES(1); + if ((arg_len = is_keyword(ptr, len, "alloc"))) + uc->data |= DEBUG_ALLOC; + else if ((arg_len = is_keyword(ptr, len, "poll"))) + uc->data |= DEBUG_POLL; + else if ((arg_len = is_keyword(ptr, len, "queue"))) + uc->data |= DEBUG_QUEUE; + else if ((arg_len = is_keyword(ptr, len, "result"))) + uc->data |= DEBUG_RESULT; + else if ((arg_len = is_keyword(ptr, len, "scatter"))) + uc->data |= DEBUG_SCATTER; + else if ((arg_len = is_keyword(ptr, len, "script"))) + uc->data |= DEBUG_SCRIPT; + else if ((arg_len = is_keyword(ptr, len, "tiny"))) + uc->data |= DEBUG_TINY; + else if ((arg_len = is_keyword(ptr, len, "nego"))) + uc->data |= DEBUG_NEGO; + else if ((arg_len = is_keyword(ptr, len, "tags"))) + uc->data |= DEBUG_TAGS; + else if ((arg_len = is_keyword(ptr, len, "freeze"))) + uc->data |= DEBUG_FREEZE; + else if ((arg_len = is_keyword(ptr, len, "restart"))) + uc->data |= DEBUG_RESTART; + else + return -EINVAL; + ptr += arg_len; len -= arg_len; + } +#ifdef DEBUG_PROC_INFO +printf("ncr_user_command: data=%ld\n", uc->data); +#endif + break; + case UC_SETFLAG: + while (len > 0) { + SKIP_SPACES(1); + if ((arg_len = is_keyword(ptr, len, "trace"))) + uc->data |= UF_TRACE; + else + return -EINVAL; + ptr += arg_len; len -= arg_len; + } + break; + default: + break; + } + + /* + ** Not allow to disable tagged queue + */ + if (uc->cmd == UC_SETTAGS && uc->data < 1) + return -EINVAL; + + if (len) + return -EINVAL; +#ifdef SCSI_NCR_USER_COMMAND + else { + long flags; + + save_flags(flags); cli(); + ncr_usercmd (np); + restore_flags(flags); + } +#endif + return length; +} + +struct info_str +{ + char *buffer; + int length; + int offset; + int pos; +}; + +static void copy_mem_info(struct info_str *info, char *data, int len) +{ + if (info->pos + len > info->length) + len = info->length - info->pos; + + if (info->pos + len < info->offset) { + info->pos += len; + return; + } + if (info->pos < info->offset) { + data += (info->offset - info->pos); + len -= (info->offset - info->pos); + } + + if (len > 0) { + memcpy(info->buffer + info->pos, data, len); + info->pos += len; + } +} + +static int copy_info(struct info_str *info, char *fmt, ...) +{ + va_list args; + char buf[81]; + int len; + + va_start(args, fmt); + len = vsprintf(buf, fmt, args); + va_end(args); + + copy_mem_info(info, buf, len); + return len; +} + +/* +** Copy formatted profile information into the input buffer. +*/ + +static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len) +{ + struct info_str info; + + info.buffer = ptr; + info.length = len; + info.offset = offset; + info.pos = 0; + + copy_info(&info, "General information:\n"); + copy_info(&info, " Chip NCR53C%03d, ", np->chip); + copy_info(&info, "device id 0x%x, ", np->device_id); + copy_info(&info, "revision id 0x%x\n", np->revision_id); + + copy_info(&info, " IO port address 0x%lx, ", (u_long) np->port); + copy_info(&info, "IRQ number %d\n", (int) np->irq); + +#ifndef NCR_IOMAPPED + if (np->use_mmio) + copy_info(&info, " Using memory mapped IO at virtual address 0x%lx\n", + (u_long) np->reg_remapped); +#endif + +#ifdef SCSI_NCR_PROFILE + copy_info(&info, "Profiling information:\n"); + copy_info(&info, " %-12s = %lu\n", "num_trans",np->profile.num_trans); + copy_info(&info, " %-12s = %lu\n", "num_kbytes",np->profile.num_kbytes); + copy_info(&info, " %-12s = %lu\n", "num_disc", np->profile.num_disc); + copy_info(&info, " %-12s = %lu\n", "num_break",np->profile.num_break); + copy_info(&info, " %-12s = %lu\n", "num_int", np->profile.num_int); + copy_info(&info, " %-12s = %lu\n", "num_fly", np->profile.num_fly); + copy_info(&info, " %-12s = %lu\n", "ms_setup", np->profile.ms_setup); + copy_info(&info, " %-12s = %lu\n", "ms_data", np->profile.ms_data); + copy_info(&info, " %-12s = %lu\n", "ms_disc", np->profile.ms_disc); + copy_info(&info, " %-12s = %lu\n", "ms_post", np->profile.ms_post); +#endif + + return info.pos > info.offset? info.pos - info.offset : 0; +} + +/* +** Entry point of the scsi proc fs of the driver. +** - func = 0 means read (returns profile data) +** - func = 1 means write (parse user control command) +*/ + +int ncr53c8xx_proc_info(char *buffer, char **start, off_t offset, + int length, int hostno, int func) +{ + struct Scsi_Host *host; + struct host_data *host_data; + ncb_p ncb = 0; + int retv; + +#ifdef DEBUG_PROC_INFO +printf("ncr53c8xx_proc_info: hostno=%d, func=%d\n", hostno, func); +#endif + + for (host = first_host; host; host = host->next) { + if (host->hostt == the_template && host->host_no == hostno) { + host_data = (struct host_data *) host->hostdata; + ncb = &host_data->ncb_data; + break; + } + } + + if (!ncb) + return -EINVAL; + + if (func) { + retv = ncr_user_command(ncb, buffer, length); +#ifdef DEBUG_PROC_INFO +printf("ncr_user_command: retv=%d\n", retv); +#endif + } + else { + if (start) + *start = buffer; + retv = ncr_host_info(ncb, buffer, offset, length); + } + + return retv; +} + +/*========================================================================= +** End of proc file system stuff +**========================================================================= +*/ +#endif + +/* +** Module stuff +*/ + +#ifdef MODULE +Scsi_Host_Template driver_template = NCR53C8XX; +#include "scsi_module.c" +#endif diff -ur --new-file old/linux/drivers/scsi/ncr53c8xx.h new/linux/drivers/scsi/ncr53c8xx.h --- old/linux/drivers/scsi/ncr53c8xx.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/scsi/ncr53c8xx.h Tue Jul 23 09:26:41 1996 @@ -0,0 +1,849 @@ +/****************************************************************************** +** Device driver for the PCI-SCSI NCR538XX controller family. +** +** Copyright (C) 1994 Wolfgang Stanglmeier +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation; either version 2 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +** +**----------------------------------------------------------------------------- +** +** This driver has been ported to Linux from the FreeBSD NCR53C8XX driver +** and is currently maintained by +** +** Gerard Roudier +** +** Being given that this driver originates from the FreeBSD version, and +** in order to keep synergy on both, any suggested enhancements and corrections +** received on Linux are automatically a potential candidate for the FreeBSD +** version. +** +** The original driver has been written for 386bsd and FreeBSD by +** Wolfgang Stanglmeier +** Stefan Esser +** +** And has been ported to NetBSD by +** Charles M. Hannum +** +******************************************************************************* +*/ + +#ifndef NCR53C8XX_H +#define NCR53C8XX_H + +/*********** LINUX SPECIFIC SECTION ******************/ + +/* +** Check supported Linux versions +*/ + +#if !defined(LINUX_VERSION_CODE) +#include +#endif +#include + +/* +** During make dep of linux-1.2.13, LINUX_VERSION_CODE is undefined +** Under linux-1.3.X, all seems to be OK. +** So, we have only to define it under 1.2.13 +*/ + +#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) + +#if !defined(LINUX_VERSION_CODE) +#define LINUX_VERSION_CODE LinuxVersionCode(1,2,13) +#endif + +#if !defined(VERSION) +#define VERSION ((LINUX_VERSION_CODE >> 16) & 0xff) +#define PATCHLEVEL ((LINUX_VERSION_CODE >> 8) & 0xff) +#define SUBLEVEL ((LINUX_VERSION_CODE >> 0) & 0xff) +#endif + +#if VERSION == 0 || VERSION > 3 +# error Only Linux version 1 and probable 2 or 3 supported. +#endif + +#if VERSION == 1 && PATCHLEVEL == 2 +# if SUBLEVEL != 13 +# error Only sublevel 13 of Linux 1.2 is supported. +# endif +#endif + +#if VERSION == 1 && PATCHLEVEL == 3 +# if SUBLEVEL < 45 +# error Only sublevels >=45 of Linux 1.3 are supported. +# endif +#endif + +/* +** Normal IO or memory mapped IO. +** +** Memory mapped IO only works with linux-1.3.X +** If your motherboard does not work with memory mapped IO, +** define SCSI_NCR_IOMAPPED for PATCHLEVEL 3 too. +*/ + +#if LINUX_VERSION_CODE < LinuxVersionCode(1,3,0) +# define SCSI_NCR_IOMAPPED +#endif + +#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0) +# define SCSI_NCR_PROC_INFO_SUPPORT +#endif + +#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,72) +# define SCSI_NCR_SHARE_IRQ +#endif + +/* +** Avoid to change these constants, unless you know what you are doing. +*/ + +#define SCSI_NCR_MAX_TAGS (4) +#define SCSI_NCR_ALWAYS_SIMPLE_TAG + +#ifdef CONFIG_SCSI_NCR53C8XX_IOMAPPED +#define SCSI_NCR_IOMAPPED +#endif + +#ifndef CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE +#define SCSI_NCR_TAGGED_QUEUE_DISABLED +#endif + +#ifdef CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT +#define SCSI_NCR_NO_DISCONNECT +#endif + +#ifdef CONFIG_SCSI_NCR53C8XX_FORCE_ASYNCHRONOUS +#define SCSI_NCR_FORCE_ASYNCHRONOUS +#endif + +#ifdef CONFIG_SCSI_NCR53C8XX_FORCE_SYNC_NEGO +#define SCSI_NCR_FORCE_SYNC_NEGO +#endif + +#ifdef CONFIG_SCSI_NCR53C8XX_DISABLE_MPARITY_CHECK +#define SCSI_NCR_DISABLE_MPARITY_CHECK +#endif + +#ifdef CONFIG_SCSI_NCR53C8XX_DISABLE_PARITY_CHECK +#define SCSI_NCR_DISABLE_PARITY_CHECK +#endif + +#if 0 +#define SCSI_NCR_SEGMENT_SIZE (512) +#endif + +#define SCSI_NCR_MAX_SCATTER (128) +#define SCSI_NCR_MAX_TARGET (16) +#define SCSI_NCR_MAX_HOST (2) +#define SCSI_NCR_SETTLE_TIME (2) +#define SCSI_NCR_TIMEOUT_ALERT (3*HZ) + +#define SCSI_NCR_CAN_QUEUE (7*SCSI_NCR_MAX_TAGS) +#define SCSI_NCR_CMD_PER_LUN (SCSI_NCR_MAX_TAGS) +#define SCSI_NCR_SG_TABLESIZE (SCSI_NCR_MAX_SCATTER-1) + +#if 1 /* defined CONFIG_SCSI_MULTI_LUN */ +#define SCSI_NCR_MAX_LUN (8) +#else +#define SCSI_NCR_MAX_LUN (1) +#endif + +#define SCSI_NCR_TIMER_INTERVAL ((HZ+5-1)/5) + +/* +** Define Scsi_Host_Template parameters +** +** Used by hosts.c and ncr53c8xx.c with module configuration. +*/ + +#if defined(HOSTS_C) || defined(MODULE) + +#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,98) +#include +#else +#include +#endif + +int ncr53c8xx_abort(Scsi_Cmnd *); +int ncr53c8xx_detect(Scsi_Host_Template *tpnt); +int ncr53c8xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); + +#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,98) +int ncr53c8xx_reset(Scsi_Cmnd *, unsigned int); +#else +int ncr53c8xx_reset(Scsi_Cmnd *); +#endif + +#ifdef MODULE +int ncr53c8xx_release(struct Scsi_Host *); +#else +#define ncr53c8xx_release NULL +#endif + +#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0) + +#define NCR53C8XX {NULL,NULL,NULL,NULL,"ncr53c8xx (rel 1.12b)", ncr53c8xx_detect,\ + ncr53c8xx_release, /* info */ NULL, /* command, deprecated */ NULL, \ + ncr53c8xx_queue_command, ncr53c8xx_abort, ncr53c8xx_reset, \ + NULL /* slave attach */, scsicam_bios_param, /* can queue */ SCSI_NCR_CAN_QUEUE,\ + /* id */ 7, SCSI_NCR_SG_TABLESIZE /* SG */, /* cmd per lun */ SCSI_NCR_CMD_PER_LUN, \ + /* present */ 0, /* unchecked isa dma */ 0, DISABLE_CLUSTERING} + + +#else + + +#define NCR53C8XX {NULL, NULL, "ncr53c8xx (rel 1.12b)", ncr53c8xx_detect,\ + ncr53c8xx_release, /* info */ NULL, /* command, deprecated */ NULL, \ + ncr53c8xx_queue_command, ncr53c8xx_abort, ncr53c8xx_reset, \ + NULL /* slave attach */, scsicam_bios_param, /* can queue */ SCSI_NCR_CAN_QUEUE,\ + /* id */ 7, SCSI_NCR_SG_TABLESIZE /* SG */, /* cmd per lun */ SCSI_NCR_CMD_PER_LUN, \ + /* present */ 0, /* unchecked isa dma */ 0, DISABLE_CLUSTERING} + +#endif /* LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0) */ + +#endif /* defined(HOSTS_C) || defined(MODULE) */ + + +#ifndef HOSTS_C + +/* +** Define the table of target capabilities by host and target +** +** If you have problems with a scsi device, note the host unit and the +** corresponding target number. +** +** Edit the corresponding entry of the table below and try successively: +** NQ7_Questionnable +** NQ7_IdeLike +** +** This bitmap is anded with the byte 7 of inquiry data on completion of +** INQUIRY command. +** The driver never see the zeroed bits and will ignore the corresponding +** capabilities of the target. +*/ + +#define INQ7_SftRe 1 +#define INQ7_CmdQueue (1<<1) /* Tagged Command */ +#define INQ7_Reserved (1<<2) +#define INQ7_Linked (1<<3) +#define INQ7_Sync (1<<4) /* Synchronous Negotiation */ +#define INQ7_WBus16 (1<<5) +#define INQ7_WBus32 (1<<6) +#define INQ7_RelAdr (1<<7) + +#define INQ7_IdeLike 0 +#define INQ7_Scsi1Like INQ7_IdeLike +#define INQ7_Perfect 0xff +#define INQ7_Questionnable ~(INQ7_CmdQueue|INQ7_Sync) +#define INQ7_VeryQuestionnable \ + ~(INQ7_CmdQueue|INQ7_Sync|INQ7_WBus16|INQ7_WBus32) + +#define INQ7_Default INQ7_Perfect + +#define NCR53C8XX_TARGET_CAPABILITIES \ +/* Host 0 */ \ +{ \ + { \ + /* Target 0 */ INQ7_Default, \ + /* Target 1 */ INQ7_Default, \ + /* Target 2 */ INQ7_Default, \ + /* Target 3 */ INQ7_Default, \ + /* Target 4 */ INQ7_Default, \ + /* Target 5 */ INQ7_Default, \ + /* Target 6 */ INQ7_Default, \ + /* Target 7 */ INQ7_Default, \ + /* Target 8 */ INQ7_Default, \ + /* Target 9 */ INQ7_Default, \ + /* Target 10 */ INQ7_Default, \ + /* Target 11 */ INQ7_Default, \ + /* Target 12 */ INQ7_Default, \ + /* Target 13 */ INQ7_Default, \ + /* Target 14 */ INQ7_Default, \ + /* Target 15 */ INQ7_Default, \ + } \ +}, \ +/* Host 1 */ \ +{ \ + { \ + /* Target 0 */ INQ7_Default, \ + /* Target 1 */ INQ7_Default, \ + /* Target 2 */ INQ7_Default, \ + /* Target 3 */ INQ7_Default, \ + /* Target 4 */ INQ7_Default, \ + /* Target 5 */ INQ7_Default, \ + /* Target 6 */ INQ7_Default, \ + /* Target 7 */ INQ7_Default, \ + /* Target 8 */ INQ7_Default, \ + /* Target 9 */ INQ7_Default, \ + /* Target 10 */ INQ7_Default, \ + /* Target 11 */ INQ7_Default, \ + /* Target 12 */ INQ7_Default, \ + /* Target 13 */ INQ7_Default, \ + /* Target 14 */ INQ7_Default, \ + /* Target 15 */ INQ7_Default, \ + } \ +} + +/* +** Replace the proc_dir_entry of the standard ncr driver. +*/ + +#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0) +#if defined(CONFIG_SCSI_NCR53C7xx) || !defined(CONFIG_SCSI_NCR53C8XX) +#define PROC_SCSI_NCR53C8XX PROC_SCSI_NCR53C7xx +#endif +#endif + +/* +** NCR53C8XX Device Ids +*/ + +#ifndef PCI_DEVICE_ID_NCR_53C810 +#define PCI_DEVICE_ID_NCR_53C810 1 +#endif + +#ifndef PCI_DEVICE_ID_NCR_53C810AP +#define PCI_DEVICE_ID_NCR_53C810AP 5 +#endif + +#ifndef PCI_DEVICE_ID_NCR_53C815 +#define PCI_DEVICE_ID_NCR_53C815 4 +#endif + +#ifndef PCI_DEVICE_ID_NCR_53C820 +#define PCI_DEVICE_ID_NCR_53C820 2 +#endif + +#ifndef PCI_DEVICE_ID_NCR_53C825 +#define PCI_DEVICE_ID_NCR_53C825 3 +#endif + +#ifndef PCI_DEVICE_ID_NCR_53C860 +#define PCI_DEVICE_ID_NCR_53C860 6 +#endif + +#ifndef PCI_DEVICE_ID_NCR_53C875 +#define PCI_DEVICE_ID_NCR_53C875 0xf +#endif + +/**************** ORIGINAL CONTENT of ncrreg.h from FreeBSD ******************/ + +/*----------------------------------------------------------------- +** +** The ncr 53c810 register structure. +** +**----------------------------------------------------------------- +*/ + +struct ncr_reg { +/*00*/ u_char nc_scntl0; /* full arb., ena parity, par->ATN */ + +/*01*/ u_char nc_scntl1; /* no reset */ + #define ISCON 0x10 /* connected to scsi */ + #define CRST 0x08 /* force reset */ + +/*02*/ u_char nc_scntl2; /* no disconnect expected */ + #define SDU 0x80 /* cmd: disconnect will raise error */ + #define CHM 0x40 /* sta: chained mode */ + #define WSS 0x08 /* sta: wide scsi send [W]*/ + #define WSR 0x01 /* sta: wide scsi received [W]*/ + +/*03*/ u_char nc_scntl3; /* cnf system clock dependent */ + #define EWS 0x08 /* cmd: enable wide scsi [W]*/ + +/*04*/ u_char nc_scid; /* cnf host adapter scsi address */ + #define RRE 0x40 /* r/w:e enable response to resel. */ + #define SRE 0x20 /* r/w:e enable response to select */ + +/*05*/ u_char nc_sxfer; /* ### Sync speed and count */ + +/*06*/ u_char nc_sdid; /* ### Destination-ID */ + +/*07*/ u_char nc_gpreg; /* ??? IO-Pins */ + +/*08*/ u_char nc_sfbr; /* ### First byte in phase */ + +/*09*/ u_char nc_socl; + #define CREQ 0x80 /* r/w: SCSI-REQ */ + #define CACK 0x40 /* r/w: SCSI-ACK */ + #define CBSY 0x20 /* r/w: SCSI-BSY */ + #define CSEL 0x10 /* r/w: SCSI-SEL */ + #define CATN 0x08 /* r/w: SCSI-ATN */ + #define CMSG 0x04 /* r/w: SCSI-MSG */ + #define CC_D 0x02 /* r/w: SCSI-C_D */ + #define CI_O 0x01 /* r/w: SCSI-I_O */ + +/*0a*/ u_char nc_ssid; + +/*0b*/ u_char nc_sbcl; + +/*0c*/ u_char nc_dstat; + #define DFE 0x80 /* sta: dma fifo empty */ + #define MDPE 0x40 /* int: master data parity error */ + #define BF 0x20 /* int: script: bus fault */ + #define ABRT 0x10 /* int: script: command aborted */ + #define SSI 0x08 /* int: script: single step */ + #define SIR 0x04 /* int: script: interrupt instruct. */ + #define IID 0x01 /* int: script: illegal instruct. */ + +/*0d*/ u_char nc_sstat0; + #define ILF 0x80 /* sta: data in SIDL register lsb */ + #define ORF 0x40 /* sta: data in SODR register lsb */ + #define OLF 0x20 /* sta: data in SODL register lsb */ + #define AIP 0x10 /* sta: arbitration in progress */ + #define LOA 0x08 /* sta: arbitration lost */ + #define WOA 0x04 /* sta: arbitration won */ + #define IRST 0x02 /* sta: scsi reset signal */ + #define SDP 0x01 /* sta: scsi parity signal */ + +/*0e*/ u_char nc_sstat1; + #define FF3210 0xf0 /* sta: bytes in the scsi fifo */ + +/*0f*/ u_char nc_sstat2; + #define ILF1 0x80 /* sta: data in SIDL register msb[W]*/ + #define ORF1 0x40 /* sta: data in SODR register msb[W]*/ + #define OLF1 0x20 /* sta: data in SODL register msb[W]*/ + #define LDSC 0x02 /* sta: disconnect & reconnect */ + +/*10*/ u_int32 nc_dsa; /* --> Base page */ + +/*14*/ u_char nc_istat; /* --> Main Command and status */ + #define CABRT 0x80 /* cmd: abort current operation */ + #define SRST 0x40 /* mod: reset chip */ + #define SIGP 0x20 /* r/w: message from host to ncr */ + #define SEM 0x10 /* r/w: message between host + ncr */ + #define CON 0x08 /* sta: connected to scsi */ + #define INTF 0x04 /* sta: int on the fly (reset by wr)*/ + #define SIP 0x02 /* sta: scsi-interrupt */ + #define DIP 0x01 /* sta: host/script interrupt */ + +/*15*/ u_char nc_15_; +/*16*/ u_char nc_16_; +/*17*/ u_char nc_17_; + +/*18*/ u_char nc_ctest0; +/*19*/ u_char nc_ctest1; + +/*1a*/ u_char nc_ctest2; + #define CSIGP 0x40 + +/*1b*/ u_char nc_ctest3; + #define CLF 0x04 /* clear scsi fifo */ + +/*1c*/ u_int32 nc_temp; /* ### Temporary stack */ + +/*20*/ u_char nc_dfifo; +/*21*/ u_char nc_ctest4; +/*22*/ u_char nc_ctest5; +/*23*/ u_char nc_ctest6; + +/*24*/ u_int32 nc_dbc; /* ### Byte count and command */ +/*28*/ u_int32 nc_dnad; /* ### Next command register */ +/*2c*/ u_int32 nc_dsp; /* --> Script Pointer */ +/*30*/ u_int32 nc_dsps; /* --> Script pointer save/opcode#2 */ +/*34*/ u_int32 nc_scratcha; /* ??? Temporary register a */ + +/*38*/ u_char nc_dmode; +/*39*/ u_char nc_dien; +/*3a*/ u_char nc_dwt; + +/*3b*/ u_char nc_dcntl; /* --> Script execution control */ + #define SSM 0x10 /* mod: single step mode */ + #define STD 0x04 /* cmd: start dma mode */ + #define NOCOM 0x01 /* cmd: protect sfbr while reselect */ + +/*3c*/ u_int32 nc_adder; + +/*40*/ u_short nc_sien; /* -->: interrupt enable */ +/*42*/ u_short nc_sist; /* <--: interrupt status */ + #define STO 0x0400/* sta: timeout (select) */ + #define GEN 0x0200/* sta: timeout (general) */ + #define HTH 0x0100/* sta: timeout (handshake) */ + #define MA 0x80 /* sta: phase mismatch */ + #define CMP 0x40 /* sta: arbitration complete */ + #define SEL 0x20 /* sta: selected by another device */ + #define RSL 0x10 /* sta: reselected by another device*/ + #define SGE 0x08 /* sta: gross error (over/underflow)*/ + #define UDC 0x04 /* sta: unexpected disconnect */ + #define RST 0x02 /* sta: scsi bus reset detected */ + #define PAR 0x01 /* sta: scsi parity error */ + +/*44*/ u_char nc_slpar; +/*45*/ u_char nc_swide; +/*46*/ u_char nc_macntl; +/*47*/ u_char nc_gpcntl; +/*48*/ u_char nc_stime0; /* cmd: timeout for select&handshake*/ +/*49*/ u_char nc_stime1; /* cmd: timeout user defined */ +/*4a*/ u_short nc_respid; /* sta: Reselect-IDs */ + +/*4c*/ u_char nc_stest0; + +/*4d*/ u_char nc_stest1; + +/*4e*/ u_char nc_stest2; + #define ROF 0x40 /* reset scsi offset (after gross error!) */ + #define EXT 0x02 /* extended filtering */ + +/*4f*/ u_char nc_stest3; + #define TE 0x80 /* c: tolerAnt enable */ + #define CSF 0x02 /* c: clear scsi fifo */ + +/*50*/ u_short nc_sidl; /* Lowlevel: latched from scsi data */ +/*52*/ u_short nc_52_; +/*54*/ u_short nc_sodl; /* Lowlevel: data out to scsi data */ +/*56*/ u_short nc_56_; +/*58*/ u_short nc_sbdl; /* Lowlevel: data from scsi data */ +/*5a*/ u_short nc_5a_; +/*5c*/ u_char nc_scr0; /* Working register B */ +/*5d*/ u_char nc_scr1; /* */ +/*5e*/ u_char nc_scr2; /* */ +/*5f*/ u_char nc_scr3; /* */ +/*60*/ +}; + +/*----------------------------------------------------------- +** +** Utility macros for the script. +** +**----------------------------------------------------------- +*/ + +#define REGJ(p,r) (offsetof(struct ncr_reg, p ## r)) +#define REG(r) REGJ (nc_, r) + +#ifndef TARGET_MODE +#define TARGET_MODE 0 +#endif + +typedef u_int32 ncrcmd; + +/*----------------------------------------------------------- +** +** SCSI phases +** +**----------------------------------------------------------- +*/ + +#define SCR_DATA_OUT 0x00000000 +#define SCR_DATA_IN 0x01000000 +#define SCR_COMMAND 0x02000000 +#define SCR_STATUS 0x03000000 +#define SCR_ILG_OUT 0x04000000 +#define SCR_ILG_IN 0x05000000 +#define SCR_MSG_OUT 0x06000000 +#define SCR_MSG_IN 0x07000000 + +/*----------------------------------------------------------- +** +** Data transfer via SCSI. +** +**----------------------------------------------------------- +** +** MOVE_ABS (LEN) +** <> +** +** MOVE_IND (LEN) +** <> +** +** MOVE_TBL +** <> +** +**----------------------------------------------------------- +*/ + +#define SCR_MOVE_ABS(l) ((0x08000000 ^ (TARGET_MODE << 1ul)) | (l)) +#define SCR_MOVE_IND(l) ((0x28000000 ^ (TARGET_MODE << 1ul)) | (l)) +#define SCR_MOVE_TBL (0x18000000 ^ (TARGET_MODE << 1ul)) + +struct scr_tblmove { + u_int32 size; + u_int32 addr; +}; + +/*----------------------------------------------------------- +** +** Selection +** +**----------------------------------------------------------- +** +** SEL_ABS | SCR_ID (0..7) [ | REL_JMP] +** <> +** +** SEL_TBL | << dnad_offset>> [ | REL_JMP] +** <> +** +**----------------------------------------------------------- +*/ + +#define SCR_SEL_ABS 0x40000000 +#define SCR_SEL_ABS_ATN 0x41000000 +#define SCR_SEL_TBL 0x42000000 +#define SCR_SEL_TBL_ATN 0x43000000 + +struct scr_tblsel { + u_char sel_0; + u_char sel_sxfer; + u_char sel_id; + u_char sel_scntl3; +}; + +#define SCR_JMP_REL 0x04000000 +#define SCR_ID(id) (((u_int32)(id)) << 16) + +/*----------------------------------------------------------- +** +** Waiting for Disconnect or Reselect +** +**----------------------------------------------------------- +** +** WAIT_DISC +** dummy: <> +** +** WAIT_RESEL +** <> +** +**----------------------------------------------------------- +*/ + +#define SCR_WAIT_DISC 0x48000000 +#define SCR_WAIT_RESEL 0x50000000 + +/*----------------------------------------------------------- +** +** Bit Set / Reset +** +**----------------------------------------------------------- +** +** SET (flags {|.. }) +** +** CLR (flags {|.. }) +** +**----------------------------------------------------------- +*/ + +#define SCR_SET(f) (0x58000000 | (f)) +#define SCR_CLR(f) (0x60000000 | (f)) + +#define SCR_CARRY 0x00000400 +#define SCR_TRG 0x00000200 +#define SCR_ACK 0x00000040 +#define SCR_ATN 0x00000008 + + + + +/*----------------------------------------------------------- +** +** Memory to memory move +** +**----------------------------------------------------------- +** +** COPY (bytecount) +** << source_address >> +** << destination_address >> +** +**----------------------------------------------------------- +*/ + +#define SCR_COPY(n) (0xc0000000 | (n)) + +/*----------------------------------------------------------- +** +** Register move and binary operations +** +**----------------------------------------------------------- +** +** SFBR_REG (reg, op, data) reg = SFBR op data +** << 0 >> +** +** REG_SFBR (reg, op, data) SFBR = reg op data +** << 0 >> +** +** REG_REG (reg, op, data) reg = reg op data +** << 0 >> +** +**----------------------------------------------------------- +*/ + +#define SCR_REG_OFS(ofs) ((ofs) << 16ul) + +#define SCR_SFBR_REG(reg,op,data) \ + (0x68000000 | (SCR_REG_OFS(REG(reg))) | (op) | ((data)<<8ul)) + +#define SCR_REG_SFBR(reg,op,data) \ + (0x70000000 | (SCR_REG_OFS(REG(reg))) | (op) | ((data)<<8ul)) + +#define SCR_REG_REG(reg,op,data) \ + (0x78000000 | (SCR_REG_OFS(REG(reg))) | (op) | ((data)<<8ul)) + + +#define SCR_LOAD 0x00000000 +#define SCR_SHL 0x01000000 +#define SCR_OR 0x02000000 +#define SCR_XOR 0x03000000 +#define SCR_AND 0x04000000 +#define SCR_SHR 0x05000000 +#define SCR_ADD 0x06000000 +#define SCR_ADDC 0x07000000 + +/*----------------------------------------------------------- +** +** FROM_REG (reg) reg = SFBR +** << 0 >> +** +** TO_REG (reg) SFBR = reg +** << 0 >> +** +** LOAD_REG (reg, data) reg = +** << 0 >> +** +** LOAD_SFBR(data) SFBR = +** << 0 >> +** +**----------------------------------------------------------- +*/ + +#define SCR_FROM_REG(reg) \ + SCR_REG_SFBR(reg,SCR_OR,0) + +#define SCR_TO_REG(reg) \ + SCR_SFBR_REG(reg,SCR_OR,0) + +#define SCR_LOAD_REG(reg,data) \ + SCR_REG_REG(reg,SCR_LOAD,data) + +#define SCR_LOAD_SFBR(data) \ + (SCR_REG_SFBR (gpreg, SCR_LOAD, data)) + +/*----------------------------------------------------------- +** +** Waiting for Disconnect or Reselect +** +**----------------------------------------------------------- +** +** JUMP [ | IFTRUE/IFFALSE ( ... ) ] +** <
> +** +** JUMPR [ | IFTRUE/IFFALSE ( ... ) ] +** <> +** +** CALL [ | IFTRUE/IFFALSE ( ... ) ] +** <
> +** +** CALLR [ | IFTRUE/IFFALSE ( ... ) ] +** <> +** +** RETURN [ | IFTRUE/IFFALSE ( ... ) ] +** <> +** +** INT [ | IFTRUE/IFFALSE ( ... ) ] +** <> +** +** INT_FLY [ | IFTRUE/IFFALSE ( ... ) ] +** <> +** +** Conditions: +** WHEN (phase) +** IF (phase) +** CARRY +** DATA (data, mask) +** +**----------------------------------------------------------- +*/ + +#define SCR_JUMP 0x80080000 +#define SCR_JUMPR 0x80880000 +#define SCR_CALL 0x88080000 +#define SCR_CALLR 0x88880000 +#define SCR_RETURN 0x90080000 +#define SCR_INT 0x98080000 +#define SCR_INT_FLY 0x98180000 + +#define IFFALSE(arg) (0x00080000 | (arg)) +#define IFTRUE(arg) (0x00000000 | (arg)) + +#define WHEN(phase) (0x00030000 | (phase)) +#define IF(phase) (0x00020000 | (phase)) + +#define DATA(D) (0x00040000 | ((D) & 0xff)) +#define MASK(D,M) (0x00040000 | (((M ^ 0xff) & 0xff) << 8ul)|((D) & 0xff)) + +#define CARRYSET (0x00200000) + +/*----------------------------------------------------------- +** +** SCSI constants. +** +**----------------------------------------------------------- +*/ + +/* +** Messages +*/ + +#define M_COMPLETE (0x00) +#define M_EXTENDED (0x01) +#define M_SAVE_DP (0x02) +#define M_RESTORE_DP (0x03) +#define M_DISCONNECT (0x04) +#define M_ID_ERROR (0x05) +#define M_ABORT (0x06) +#define M_REJECT (0x07) +#define M_NOOP (0x08) +#define M_PARITY (0x09) +#define M_LCOMPLETE (0x0a) +#define M_FCOMPLETE (0x0b) +#define M_RESET (0x0c) +#define M_ABORT_TAG (0x0d) +#define M_CLEAR_QUEUE (0x0e) +#define M_INIT_REC (0x0f) +#define M_REL_REC (0x10) +#define M_TERMINATE (0x11) +#define M_SIMPLE_TAG (0x20) +#define M_HEAD_TAG (0x21) +#define M_ORDERED_TAG (0x22) +#define M_IGN_RESIDUE (0x23) +#define M_IDENTIFY (0x80) + +#define M_X_MODIFY_DP (0x00) +#define M_X_SYNC_REQ (0x01) +#define M_X_WIDE_REQ (0x03) + +/* +** Status +*/ + +#define S_GOOD (0x00) +#define S_CHECK_COND (0x02) +#define S_COND_MET (0x04) +#define S_BUSY (0x08) +#define S_INT (0x10) +#define S_INT_COND_MET (0x14) +#define S_CONFLICT (0x18) +#define S_TERMINATED (0x20) +#define S_QUEUE_FULL (0x28) +#define S_ILLEGAL (0xff) +#define S_SENSE (0x80) + +/* + * End of ncrreg from FreeBSD + */ + +#endif /* !defined HOSTS_C */ + +#endif /* defined NCR53C8XX_H */ diff -ur --new-file old/linux/drivers/scsi/qlogicfas.c new/linux/drivers/scsi/qlogicfas.c --- old/linux/drivers/scsi/qlogicfas.c Sat May 18 10:58:34 1996 +++ new/linux/drivers/scsi/qlogicfas.c Thu Jul 11 06:41:25 1996 @@ -18,7 +18,7 @@ Reference Qlogic FAS408 Technical Manual, 53408-510-00A, May 10, 1994 (you can reference it, but it is incomplete and inaccurate in places) - Version 0.44 5/7/96 - kernel 1.2.0+, pcmcia 2.5.4+ + Version 0.45 6/9/96 - kernel 1.2.0+ Functions as standalone, loadable, and PCMCIA driver, the latter from Dave Hind's PCMCIA package. @@ -612,7 +612,7 @@ if (qlirq >= 0 && !request_irq(qlirq, ql_ihandl, 0, "qlogicfas", NULL)) host->can_queue = 1; #endif - request_region( qbase , 0x10 ,"qlogic"); + request_region( qbase , 0x10 ,"qlogicfas"); hreg = scsi_register( host , 0 ); /* no host data */ hreg->io_port = qbase; hreg->n_io_port = 16; @@ -620,7 +620,7 @@ if( qlirq != -1 ) hreg->irq = qlirq; - sprintf(qinfo, "Qlogicfas Driver version 0.44, chip %02X at %03X, IRQ %d, TPdma:%d", + sprintf(qinfo, "Qlogicfas Driver version 0.45, chip %02X at %03X, IRQ %d, TPdma:%d", qltyp, qbase, qlirq, QL_TURBO_PDMA ); host->name = qinfo; diff -ur --new-file old/linux/drivers/scsi/qlogicfas.h new/linux/drivers/scsi/qlogicfas.h --- old/linux/drivers/scsi/qlogicfas.h Sat May 18 10:58:34 1996 +++ new/linux/drivers/scsi/qlogicfas.h Thu Jul 11 06:41:25 1996 @@ -19,13 +19,13 @@ NULL, \ NULL, \ NULL, \ - qlogicfas_detect, \ + qlogicfas_detect, \ NULL, \ qlogicfas_info, \ qlogicfas_command, \ qlogicfas_queuecommand, \ - qlogicfas_abort, \ - qlogicfas_reset, \ + qlogicfas_abort, \ + qlogicfas_reset, \ NULL, \ qlogicfas_biosparam, \ 0, \ diff -ur --new-file old/linux/drivers/scsi/qlogicisp.c new/linux/drivers/scsi/qlogicisp.c --- old/linux/drivers/scsi/qlogicisp.c Wed Jun 5 12:41:03 1996 +++ new/linux/drivers/scsi/qlogicisp.c Wed Jul 10 12:11:25 1996 @@ -76,6 +76,7 @@ #define DEBUG_ISP1020 0 #define DEBUG_ISP1020_INT 0 #define DEBUG_ISP1020_SETUP 0 +#define TRACE_ISP 0 #define DEFAULT_LOOP_COUNT 1000000 @@ -83,6 +84,38 @@ #include +#if TRACE_ISP + +# define TRACE_BUF_LEN (32*1024) + +struct { + u_long next; + struct { + u_long time; + u_int index; + u_int addr; + u_char * name; + } buf[TRACE_BUF_LEN]; +} trace; + +#define TRACE(w, i, a) \ +{ \ + unsigned long flags; \ + \ + save_flags(flags); \ + cli(); \ + trace.buf[trace.next].name = (w); \ + trace.buf[trace.next].time = jiffies; \ + trace.buf[trace.next].index = (i); \ + trace.buf[trace.next].addr = (long) (a); \ + trace.next = (trace.next + 1) & (TRACE_BUF_LEN - 1); \ + restore_flags(flags); \ +} + +#else +# define TRACE(w, i, a) +#endif + #if DEBUG_ISP1020 #define ENTER(x) printk("isp1020 : entering %s()\n", x); #define LEAVE(x) printk("isp1020 : leaving %s()\n", x); @@ -146,10 +179,10 @@ #define EXECUTION_TIMEOUT_RESET 0x8006 struct Entry_header { - u_char entry_type; - u_char entry_cnt; - u_char sys_def_1; - u_char flags; + u_char entry_type; + u_char entry_cnt; + u_char sys_def_1; + u_char flags; }; /* entry header type commands */ @@ -166,25 +199,22 @@ #define EFLAG_BAD_PAYLOAD 8 struct dataseg { - u_int d_base; - u_int d_count; + u_int d_base; + u_int d_count; }; struct Command_Entry { - struct Entry_header hdr; - u_int handle; - u_char target_lun; - u_char target_id; - u_short cdb_length; - u_short control_flags; - u_short rsvd; - u_short time_out; - u_short segment_cnt; - u_char cdb[12]; - struct dataseg dataseg0; - struct dataseg dataseg1; - struct dataseg dataseg2; - struct dataseg dataseg3; + struct Entry_header hdr; + u_int handle; + u_char target_lun; + u_char target_id; + u_short cdb_length; + u_short control_flags; + u_short rsvd; + u_short time_out; + u_short segment_cnt; + u_char cdb[12]; + struct dataseg dataseg[4]; }; /* command entry control flag definitions */ @@ -197,38 +227,32 @@ #define CFLAG_WRITE 0x40 struct Ext_Command_Entry { - struct Entry_header hdr; - u_int handle; - u_char target_lun; - u_char target_id; - u_short cdb_length; - u_short control_flags; - u_short rsvd; - u_short time_out; - u_short segment_cnt; - u_char cdb[44]; + struct Entry_header hdr; + u_int handle; + u_char target_lun; + u_char target_id; + u_short cdb_length; + u_short control_flags; + u_short rsvd; + u_short time_out; + u_short segment_cnt; + u_char cdb[44]; }; struct Continuation_Entry { - struct Entry_header hdr; - u_int reserved; - struct dataseg dataseg0; - struct dataseg dataseg1; - struct dataseg dataseg2; - struct dataseg dataseg3; - struct dataseg dataseg4; - struct dataseg dataseg5; - struct dataseg dataseg6; + struct Entry_header hdr; + u_int reserved; + struct dataseg dataseg[7]; }; struct Marker_Entry { - struct Entry_header hdr; - u_int reserved; - u_char target_lun; - u_char target_id; - u_char modifier; - u_char rsvd; - u_char rsvds[52]; + struct Entry_header hdr; + u_int reserved; + u_char target_lun; + u_char target_id; + u_char modifier; + u_char rsvd; + u_char rsvds[52]; }; /* marker entry modifier definitions */ @@ -237,17 +261,17 @@ #define SYNC_ALL 2 struct Status_Entry { - struct Entry_header hdr; - u_int handle; - u_short scsi_status; - u_short completion_status; - u_short state_flags; - u_short status_flags; - u_short time; - u_short req_sense_len; - u_int residual; - u_char rsvd[8]; - u_char req_sense_data[32]; + struct Entry_header hdr; + u_int handle; + u_short scsi_status; + u_short completion_status; + u_short state_flags; + u_short status_flags; + u_short time; + u_short req_sense_len; + u_int residual; + u_char rsvd[8]; + u_char req_sense_data[32]; }; /* status entry completion status definitions */ @@ -366,93 +390,93 @@ #define PACKB(a, b) (((a)<<4)|(b)) -u_char mbox_param[] = { - PACKB(1, 1), /* MBOX_NO_OP */ - PACKB(5, 5), /* MBOX_LOAD_RAM */ - PACKB(2, 0), /* MBOX_EXEC_FIRMWARE */ - PACKB(5, 5), /* MBOX_DUMP_RAM */ - PACKB(3, 3), /* MBOX_WRITE_RAM_WORD */ - PACKB(2, 3), /* MBOX_READ_RAM_WORD */ - PACKB(6, 6), /* MBOX_MAILBOX_REG_TEST */ - PACKB(2, 3), /* MBOX_VERIFY_CHECKSUM */ - PACKB(1, 3), /* MBOX_ABOUT_FIRMWARE */ - PACKB(0, 0), /* 0x0009 */ - PACKB(0, 0), /* 0x000a */ - PACKB(0, 0), /* 0x000b */ - PACKB(0, 0), /* 0x000c */ - PACKB(0, 0), /* 0x000d */ - PACKB(1, 2), /* MBOX_CHECK_FIRMWARE */ - PACKB(0, 0), /* 0x000f */ - PACKB(5, 5), /* MBOX_INIT_REQ_QUEUE */ - PACKB(6, 6), /* MBOX_INIT_RES_QUEUE */ - PACKB(4, 4), /* MBOX_EXECUTE_IOCB */ - PACKB(2, 2), /* MBOX_WAKE_UP */ - PACKB(1, 6), /* MBOX_STOP_FIRMWARE */ - PACKB(4, 4), /* MBOX_ABORT */ - PACKB(2, 2), /* MBOX_ABORT_DEVICE */ - PACKB(3, 3), /* MBOX_ABORT_TARGET */ - PACKB(2, 2), /* MBOX_BUS_RESET */ - PACKB(2, 3), /* MBOX_STOP_QUEUE */ - PACKB(2, 3), /* MBOX_START_QUEUE */ - PACKB(2, 3), /* MBOX_SINGLE_STEP_QUEUE */ - PACKB(2, 3), /* MBOX_ABORT_QUEUE */ - PACKB(2, 4), /* MBOX_GET_DEV_QUEUE_STATUS */ - PACKB(0, 0), /* 0x001e */ - PACKB(1, 3), /* MBOX_GET_FIRMWARE_STATUS */ - PACKB(1, 2), /* MBOX_GET_INIT_SCSI_ID */ - PACKB(1, 2), /* MBOX_GET_SELECT_TIMEOUT */ - PACKB(1, 3), /* MBOX_GET_RETRY_COUNT */ - PACKB(1, 2), /* MBOX_GET_TAG_AGE_LIMIT */ - PACKB(1, 2), /* MBOX_GET_CLOCK_RATE */ - PACKB(1, 2), /* MBOX_GET_ACT_NEG_STATE */ - PACKB(1, 2), /* MBOX_GET_ASYNC_DATA_SETUP_TIME */ - PACKB(1, 3), /* MBOX_GET_PCI_PARAMS */ - PACKB(2, 4), /* MBOX_GET_TARGET_PARAMS */ - PACKB(2, 4), /* MBOX_GET_DEV_QUEUE_PARAMS */ - PACKB(0, 0), /* 0x002a */ - PACKB(0, 0), /* 0x002b */ - PACKB(0, 0), /* 0x002c */ - PACKB(0, 0), /* 0x002d */ - PACKB(0, 0), /* 0x002e */ - PACKB(0, 0), /* 0x002f */ - PACKB(2, 2), /* MBOX_SET_INIT_SCSI_ID */ - PACKB(2, 2), /* MBOX_SET_SELECT_TIMEOUT */ - PACKB(3, 3), /* MBOX_SET_RETRY_COUNT */ - PACKB(2, 2), /* MBOX_SET_TAG_AGE_LIMIT */ - PACKB(2, 2), /* MBOX_SET_CLOCK_RATE */ - PACKB(2, 2), /* MBOX_SET_ACTIVE_NEG_STATE */ - PACKB(2, 2), /* MBOX_SET_ASYNC_DATA_SETUP_TIME */ - PACKB(3, 3), /* MBOX_SET_PCI_CONTROL_PARAMS */ - PACKB(4, 4), /* MBOX_SET_TARGET_PARAMS */ - PACKB(4, 4), /* MBOX_SET_DEV_QUEUE_PARAMS */ - PACKB(0, 0), /* 0x003a */ - PACKB(0, 0), /* 0x003b */ - PACKB(0, 0), /* 0x003c */ - PACKB(0, 0), /* 0x003d */ - PACKB(0, 0), /* 0x003e */ - PACKB(0, 0), /* 0x003f */ - PACKB(1, 2), /* MBOX_RETURN_BIOS_BLOCK_ADDR */ - PACKB(6, 1), /* MBOX_WRITE_FOUR_RAM_WORDS */ - PACKB(2, 3) /* MBOX_EXEC_BIOS_IOCB */ +const u_char mbox_param[] = { + PACKB(1, 1), /* MBOX_NO_OP */ + PACKB(5, 5), /* MBOX_LOAD_RAM */ + PACKB(2, 0), /* MBOX_EXEC_FIRMWARE */ + PACKB(5, 5), /* MBOX_DUMP_RAM */ + PACKB(3, 3), /* MBOX_WRITE_RAM_WORD */ + PACKB(2, 3), /* MBOX_READ_RAM_WORD */ + PACKB(6, 6), /* MBOX_MAILBOX_REG_TEST */ + PACKB(2, 3), /* MBOX_VERIFY_CHECKSUM */ + PACKB(1, 3), /* MBOX_ABOUT_FIRMWARE */ + PACKB(0, 0), /* 0x0009 */ + PACKB(0, 0), /* 0x000a */ + PACKB(0, 0), /* 0x000b */ + PACKB(0, 0), /* 0x000c */ + PACKB(0, 0), /* 0x000d */ + PACKB(1, 2), /* MBOX_CHECK_FIRMWARE */ + PACKB(0, 0), /* 0x000f */ + PACKB(5, 5), /* MBOX_INIT_REQ_QUEUE */ + PACKB(6, 6), /* MBOX_INIT_RES_QUEUE */ + PACKB(4, 4), /* MBOX_EXECUTE_IOCB */ + PACKB(2, 2), /* MBOX_WAKE_UP */ + PACKB(1, 6), /* MBOX_STOP_FIRMWARE */ + PACKB(4, 4), /* MBOX_ABORT */ + PACKB(2, 2), /* MBOX_ABORT_DEVICE */ + PACKB(3, 3), /* MBOX_ABORT_TARGET */ + PACKB(2, 2), /* MBOX_BUS_RESET */ + PACKB(2, 3), /* MBOX_STOP_QUEUE */ + PACKB(2, 3), /* MBOX_START_QUEUE */ + PACKB(2, 3), /* MBOX_SINGLE_STEP_QUEUE */ + PACKB(2, 3), /* MBOX_ABORT_QUEUE */ + PACKB(2, 4), /* MBOX_GET_DEV_QUEUE_STATUS */ + PACKB(0, 0), /* 0x001e */ + PACKB(1, 3), /* MBOX_GET_FIRMWARE_STATUS */ + PACKB(1, 2), /* MBOX_GET_INIT_SCSI_ID */ + PACKB(1, 2), /* MBOX_GET_SELECT_TIMEOUT */ + PACKB(1, 3), /* MBOX_GET_RETRY_COUNT */ + PACKB(1, 2), /* MBOX_GET_TAG_AGE_LIMIT */ + PACKB(1, 2), /* MBOX_GET_CLOCK_RATE */ + PACKB(1, 2), /* MBOX_GET_ACT_NEG_STATE */ + PACKB(1, 2), /* MBOX_GET_ASYNC_DATA_SETUP_TIME */ + PACKB(1, 3), /* MBOX_GET_PCI_PARAMS */ + PACKB(2, 4), /* MBOX_GET_TARGET_PARAMS */ + PACKB(2, 4), /* MBOX_GET_DEV_QUEUE_PARAMS */ + PACKB(0, 0), /* 0x002a */ + PACKB(0, 0), /* 0x002b */ + PACKB(0, 0), /* 0x002c */ + PACKB(0, 0), /* 0x002d */ + PACKB(0, 0), /* 0x002e */ + PACKB(0, 0), /* 0x002f */ + PACKB(2, 2), /* MBOX_SET_INIT_SCSI_ID */ + PACKB(2, 2), /* MBOX_SET_SELECT_TIMEOUT */ + PACKB(3, 3), /* MBOX_SET_RETRY_COUNT */ + PACKB(2, 2), /* MBOX_SET_TAG_AGE_LIMIT */ + PACKB(2, 2), /* MBOX_SET_CLOCK_RATE */ + PACKB(2, 2), /* MBOX_SET_ACTIVE_NEG_STATE */ + PACKB(2, 2), /* MBOX_SET_ASYNC_DATA_SETUP_TIME */ + PACKB(3, 3), /* MBOX_SET_PCI_CONTROL_PARAMS */ + PACKB(4, 4), /* MBOX_SET_TARGET_PARAMS */ + PACKB(4, 4), /* MBOX_SET_DEV_QUEUE_PARAMS */ + PACKB(0, 0), /* 0x003a */ + PACKB(0, 0), /* 0x003b */ + PACKB(0, 0), /* 0x003c */ + PACKB(0, 0), /* 0x003d */ + PACKB(0, 0), /* 0x003e */ + PACKB(0, 0), /* 0x003f */ + PACKB(1, 2), /* MBOX_RETURN_BIOS_BLOCK_ADDR */ + PACKB(6, 1), /* MBOX_WRITE_FOUR_RAM_WORDS */ + PACKB(2, 3) /* MBOX_EXEC_BIOS_IOCB */ }; #define MAX_MBOX_COMMAND (sizeof(mbox_param)/sizeof(u_short)) struct host_param { - u_short fifo_threshold; - u_short host_adapter_enable; - u_short initiator_scsi_id; - u_short bus_reset_delay; - u_short retry_count; - u_short retry_delay; - u_short async_data_setup_time; - u_short req_ack_active_negation; - u_short data_line_active_negation; - u_short data_dma_burst_enable; - u_short command_dma_burst_enable; - u_short tag_aging; - u_short selection_timeout; - u_short max_queue_depth; + u_short fifo_threshold; + u_short host_adapter_enable; + u_short initiator_scsi_id; + u_short bus_reset_delay; + u_short retry_count; + u_short retry_delay; + u_short async_data_setup_time; + u_short req_ack_active_negation; + u_short data_line_active_negation; + u_short data_dma_burst_enable; + u_short command_dma_burst_enable; + u_short tag_aging; + u_short selection_timeout; + u_short max_queue_depth; }; /* @@ -471,1082 +495,1219 @@ */ struct dev_param { - u_short device_flags; - u_short execution_throttle; - u_short synchronous_period; - u_short synchronous_offset; - u_short device_enable; - u_short reserved; /* pad */ + u_short device_flags; + u_short execution_throttle; + u_short synchronous_period; + u_short synchronous_offset; + u_short device_enable; + u_short reserved; /* pad */ }; -#define REQ_QUEUE_LEN 32 -#define RES_QUEUE_LEN 32 +/* + * The result queue can be quite a bit smaller since continuation entries + * do not show up there: + */ +#define RES_QUEUE_LEN ((QLOGICISP_REQ_QUEUE_LEN + 1) / 8 - 1) #define QUEUE_ENTRY_LEN 64 struct isp1020_hostdata { - u_int io_base; - u_char irq; - u_char bus; - u_char revision; - u_char device_fn; - u_short res_queue_in_ptr; - u_short res_queue_out_ptr; - u_short req_queue_in_ptr; - u_short req_queue_out_ptr; - struct host_param host_param; - struct dev_param dev_param[MAX_TARGETS]; - char res_queue[RES_QUEUE_LEN][QUEUE_ENTRY_LEN]; - char req_queue[REQ_QUEUE_LEN][QUEUE_ENTRY_LEN]; -}; + u_char bus; + u_char revision; + u_char device_fn; + struct host_param host_param; + struct dev_param dev_param[MAX_TARGETS]; + + /* result and request queues (shared with isp1020): */ + u_int req_in_ptr; /* index of next request slot */ + u_int res_out_ptr; /* index of next result slot */ -struct isp1020_hostdata *irq2host[NR_IRQS]; + /* this is here so the queues are nicely aligned */ + long send_marker; /* do we need to send a marker? */ -void isp1020_enable_irqs(struct isp1020_hostdata *); -void isp1020_disable_irqs(struct isp1020_hostdata *); -int isp1020_init(struct Scsi_Host *); -int isp1020_reset_hardware(struct isp1020_hostdata *); -int isp1020_get_defaults(struct isp1020_hostdata *); -int isp1020_set_defaults(struct isp1020_hostdata *); -int isp1020_load_parameters(struct isp1020_hostdata *); -int isp1020_mbox_command(struct isp1020_hostdata *, u_short []); -u_short isp1020_read_nvram_word(struct isp1020_hostdata *, u_short); -int isp1020_verify_nvram(struct isp1020_hostdata *); -void isp1020_print_status_entry(struct Status_Entry *); -void isp1020_print_scsi_cmd(Scsi_Cmnd *); -void isp1020_scsi_done(Scsi_Cmnd *); -int isp1020_return_status(struct Status_Entry *); -void isp1020_intr_handler(int, void *, struct pt_regs *); - -struct proc_dir_entry proc_scsi_isp1020 = { - PROC_SCSI_QLOGICISP, 7, "isp1020", - S_IFDIR | S_IRUGO | S_IXUGO, 2 + char res[RES_QUEUE_LEN+1][QUEUE_ENTRY_LEN]; + char req[QLOGICISP_REQ_QUEUE_LEN+1][QUEUE_ENTRY_LEN]; }; -int isp1020_detect(Scsi_Host_Template *tmpt) -{ - int hosts = 0; - u_short index; - u_char bus, device_fn; - struct Scsi_Host *scsihost; - struct isp1020_hostdata *hostdata; +/* queue length's _must_ be power of two: */ +#define QUEUE_DEPTH(in, out, ql) ((in - out) & (ql)) +#define REQ_QUEUE_DEPTH(in, out) QUEUE_DEPTH(in, out, \ + QLOGICISP_REQ_QUEUE_LEN) +#define RES_QUEUE_DEPTH(in, out) QUEUE_DEPTH(in, out, RES_QUEUE_LEN) + +struct Scsi_Host *irq2host[NR_IRQS]; + +static void isp1020_enable_irqs(struct Scsi_Host *); +static void isp1020_disable_irqs(struct Scsi_Host *); +static int isp1020_init(struct Scsi_Host *); +static int isp1020_reset_hardware(struct Scsi_Host *); +static int isp1020_set_defaults(struct Scsi_Host *); +static int isp1020_load_parameters(struct Scsi_Host *); +static int isp1020_mbox_command(struct Scsi_Host *, u_short []); +static int isp1020_return_status(struct Status_Entry *); +static void isp1020_intr_handler(int, void *, struct pt_regs *); + +#if USE_NVRAM_DEFAULTS +static int isp1020_get_defaults(struct Scsi_Host *); +static int isp1020_verify_nvram(struct Scsi_Host *); +static u_short isp1020_read_nvram_word(struct Scsi_Host *, u_short); +#endif + +#if DEBUG_ISP1020 +static void isp1020_print_scsi_cmd(Scsi_Cmnd *); +#endif +#if DEBUG_ISP1020_INTR +static void isp1020_print_status_entry(struct Status_Entry *); +#endif - ENTER("isp1020_detect"); +static struct proc_dir_entry proc_scsi_isp1020 = { + PROC_SCSI_QLOGICISP, 7, "isp1020", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; - tmpt->proc_dir = &proc_scsi_isp1020; - if (pcibios_present() == 0) { - printk("qlogicisp : PCI bios not present\n"); - return 0; - } +static inline void isp1020_enable_irqs(struct Scsi_Host *host) +{ + outw(ISP_EN_INT|ISP_EN_RISC, host->io_port + PCI_INTF_CTL); +} - memset(irq2host, 0, sizeof(irq2host)); - for (index = 0; pcibios_find_device(PCI_VENDOR_ID_QLOGIC, - PCI_DEVICE_ID_QLOGIC_ISP1020, index, &bus, &device_fn) == 0; - index++) { +static inline void isp1020_disable_irqs(struct Scsi_Host *host) +{ + outw(0x0, host->io_port + PCI_INTF_CTL); +} - scsihost = scsi_register(tmpt, sizeof(struct isp1020_hostdata)); - hostdata = (struct isp1020_hostdata *) scsihost->hostdata; - memset(hostdata, 0, sizeof(struct isp1020_hostdata)); - hostdata->bus = bus; - hostdata->device_fn = device_fn; +int isp1020_detect(Scsi_Host_Template *tmpt) +{ + int hosts = 0; + u_short index; + u_char bus, device_fn; + struct Scsi_Host *host; + struct isp1020_hostdata *hostdata; + + ENTER("isp1020_detect"); + + tmpt->proc_dir = &proc_scsi_isp1020; + + if (pcibios_present() == 0) { + printk("qlogicisp : PCI bios not present\n"); + return 0; + } + + memset(irq2host, 0, sizeof(irq2host)); + + for (index = 0; pcibios_find_device(PCI_VENDOR_ID_QLOGIC, + PCI_DEVICE_ID_QLOGIC_ISP1020, + index, &bus, &device_fn) == 0; + index++) + { + host = scsi_register(tmpt, sizeof(struct isp1020_hostdata)); + hostdata = (struct isp1020_hostdata *) host->hostdata; + + memset(hostdata, 0, sizeof(struct isp1020_hostdata)); + hostdata->bus = bus; + hostdata->device_fn = device_fn; - if (isp1020_init(scsihost) || isp1020_reset_hardware(hostdata) + if (isp1020_init(host) || isp1020_reset_hardware(host) #if USE_NVRAM_DEFAULTS - || isp1020_get_defaults(hostdata) + || isp1020_get_defaults(host) #else - || isp1020_set_defaults(hostdata) + || isp1020_set_defaults(host) #endif /* USE_NVRAM_DEFAULTS */ - || isp1020_load_parameters(hostdata)) { - scsi_unregister(scsihost); - continue; - } - - scsihost->this_id = hostdata->host_param.initiator_scsi_id; - - if (request_irq(hostdata->irq, isp1020_intr_handler, SA_INTERRUPT, - "qlogicisp", NULL)) { - printk("qlogicisp : interrupt %d already in use\n", hostdata->irq); - scsi_unregister(scsihost); - continue; - } - - if (check_region(hostdata->io_base, 0xff)) { - printk("qlogicisp : i/o region 0x%04x-0x%04x already in use\n", - hostdata->io_base, hostdata->io_base + 0xff); - free_irq(hostdata->irq, NULL); - scsi_unregister(scsihost); - continue; - } - - request_region(hostdata->io_base, 0xff, "qlogicisp"); - irq2host[hostdata->irq] = hostdata; - - outw(0x0, hostdata->io_base + PCI_SEMAPHORE); - outw(HCCR_CLEAR_RISC_INTR, hostdata->io_base + HOST_HCCR); - isp1020_enable_irqs(hostdata); + || isp1020_load_parameters(host)) { + scsi_unregister(host); + continue; + } + + host->this_id = hostdata->host_param.initiator_scsi_id; + + if (request_irq(host->irq, isp1020_intr_handler, SA_INTERRUPT, + "qlogicisp", NULL)) + { + printk("qlogicisp : interrupt %d already in use\n", + host->irq); + scsi_unregister(host); + continue; + } + + if (check_region(host->io_port, 0xff)) { + printk("qlogicisp : i/o region 0x%04x-0x%04x already " + "in use\n", + host->io_port, host->io_port + 0xff); + free_irq(host->irq, NULL); + scsi_unregister(host); + continue; + } + + request_region(host->io_port, 0xff, "qlogicisp"); + irq2host[host->irq] = host; + + outw(0x0, host->io_port + PCI_SEMAPHORE); + outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); + isp1020_enable_irqs(host); - hosts++; - } + hosts++; + } - LEAVE("isp1020_detect"); + LEAVE("isp1020_detect"); - return hosts; + return hosts; } int isp1020_release(struct Scsi_Host *host) { - struct isp1020_hostdata *hostdata; + struct isp1020_hostdata *hostdata; - ENTER("isp1020_release"); + ENTER("isp1020_release"); - hostdata = (struct isp1020_hostdata *) host->hostdata; + hostdata = (struct isp1020_hostdata *) host->hostdata; - outw(0x0, hostdata->io_base + PCI_INTF_CTL); - free_irq(hostdata->irq, NULL); + outw(0x0, host->io_port + PCI_INTF_CTL); + free_irq(host->irq, NULL); - release_region(hostdata->io_base, 0xff); + release_region(host->io_port, 0xff); - LEAVE("isp1020_release"); + LEAVE("isp1020_release"); - return 0; + return 0; } const char *isp1020_info(struct Scsi_Host *host) { - static char buf[80]; - struct isp1020_hostdata *hostdata; + static char buf[80]; + struct isp1020_hostdata *hostdata; - ENTER("isp1020_info"); + ENTER("isp1020_info"); - hostdata = (struct isp1020_hostdata *) host->hostdata; - sprintf(buf, "QLogic ISP1020 SCSI on PCI bus %d device %d irq %d base 0x%x", - hostdata->bus, (hostdata->device_fn & 0xf8) >> 3, hostdata->irq, - hostdata->io_base); + hostdata = (struct isp1020_hostdata *) host->hostdata; + sprintf(buf, + "QLogic ISP1020 SCSI on PCI bus %d device %d irq %d base 0x%x", + hostdata->bus, (hostdata->device_fn & 0xf8) >> 3, host->irq, + host->io_port); - LEAVE("isp1020_info"); + LEAVE("isp1020_info"); - return buf; + return buf; } -#define REQ_QUEUE_DEPTH() \ - (hostdata->req_queue_in_ptr >= hostdata->req_queue_out_ptr \ - ? hostdata->req_queue_in_ptr - hostdata->req_queue_out_ptr \ - : (REQ_QUEUE_LEN - hostdata->req_queue_out_ptr) \ - + hostdata->req_queue_in_ptr) - - -int isp1020_queuecommand(Scsi_Cmnd *Cmnd, void (* done)(Scsi_Cmnd *)) +/* + * The middle SCSI layer ensures that queuecommand never gets invoked + * concurrently with itself or the interrupt handler (though the + * interrupt handler may call this routine as part of + * request-completion handling). + */ +int isp1020_queuecommand(Scsi_Cmnd *Cmnd, void (*done)(Scsi_Cmnd *)) { - int i, *iptr, sg_count; - struct scatterlist *sg; - struct Command_Entry *cmd; - struct isp1020_hostdata *hostdata; - unsigned long flags; - - ENTER("isp1020_queuecommand"); + int i, sg_count, n, num_free; + u_int in_ptr, out_ptr; + struct dataseg * ds; + struct scatterlist *sg; + struct Command_Entry *cmd; + struct Continuation_Entry *cont; + struct Scsi_Host *host; + struct isp1020_hostdata *hostdata; + + ENTER("isp1020_queuecommand"); + + host = Cmnd->host; + hostdata = (struct isp1020_hostdata *) host->hostdata; + Cmnd->scsi_done = done; + + DEBUG(isp1020_print_scsi_cmd(Cmnd)); + + out_ptr = inw(host->io_port + MBOX4); + in_ptr = hostdata->req_in_ptr; + + DEBUG(printk("qlogicisp : request queue depth %d\n", + REQ_QUEUE_DEPTH(in_ptr, out_ptr))); + + cmd = (struct Command_Entry *) &hostdata->req[in_ptr][0]; + in_ptr = (in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN; + if (in_ptr == out_ptr) { + printk("qlogicisp : request queue overflow\n"); + return 1; + } + + if (hostdata->send_marker) { + struct Marker_Entry *marker; + + TRACE("queue marker", in_ptr, 0); + + DEBUG(printk("qlogicisp : adding marker entry\n")); + marker = (struct Marker_Entry *) cmd; + memset(marker, 0, sizeof(struct Marker_Entry)); + + marker->hdr.entry_type = ENTRY_MARKER; + marker->hdr.entry_cnt = 1; + marker->modifier = SYNC_ALL; + + hostdata->send_marker = 0; + + if (((in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN) == out_ptr) { + outw(in_ptr, host->io_port + MBOX4); + hostdata->req_in_ptr = in_ptr; + printk("qlogicisp : request queue overflow\n"); + return 1; + } + cmd = (struct Command_Entry *) &hostdata->req[in_ptr][0]; + in_ptr = (in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN; + } + + TRACE("queue command", in_ptr, Cmnd); + + memset(cmd, 0, sizeof(struct Command_Entry)); + + cmd->hdr.entry_type = ENTRY_COMMAND; + cmd->hdr.entry_cnt = 1; + + cmd->handle = (u_int) virt_to_bus(Cmnd); + cmd->target_lun = Cmnd->lun; + cmd->target_id = Cmnd->target; + cmd->cdb_length = Cmnd->cmd_len; + cmd->control_flags = CFLAG_READ | CFLAG_WRITE; + cmd->time_out = 30; + + memcpy(cmd->cdb, Cmnd->cmnd, Cmnd->cmd_len); + + if (Cmnd->use_sg) { + cmd->segment_cnt = sg_count = Cmnd->use_sg; + sg = (struct scatterlist *) Cmnd->request_buffer; + ds = cmd->dataseg; + + /* fill in first four sg entries: */ + n = sg_count; + if (n > 4) + n = 4; + for (i = 0; i < n; i++) { + ds[i].d_base = (u_int) virt_to_bus(sg->address); + ds[i].d_count = sg->length; + ++sg; + } + sg_count -= 4; + + while (sg_count > 0) { + ++cmd->hdr.entry_cnt; + cont = (struct Continuation_Entry *) + &hostdata->req[in_ptr][0]; + in_ptr = (in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN; + if (in_ptr == out_ptr) { + printk("isp1020: unexpected request queue " + "overflow\n"); + return 1; + } + TRACE("queue continuation", in_ptr, 0); + cont->hdr.entry_type = ENTRY_CONTINUATION; + cont->hdr.entry_cnt = 0; + cont->hdr.sys_def_1 = 0; + cont->hdr.flags = 0; + cont->reserved = 0; + ds = cont->dataseg; + n = sg_count; + if (n > 7) + n = 7; + for (i = 0; i < n; ++i) { + ds[i].d_base = (u_int)virt_to_bus(sg->address); + ds[i].d_count = sg->length; + ++sg; + } + sg_count -= n; + } + } else { + cmd->dataseg[0].d_base = + (u_int) virt_to_bus(Cmnd->request_buffer); + cmd->dataseg[0].d_count = + (u_int) Cmnd->request_bufflen; + cmd->segment_cnt = 1; + } + + outw(in_ptr, host->io_port + MBOX4); + hostdata->req_in_ptr = in_ptr; + + num_free = QLOGICISP_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr); + host->can_queue = host->host_busy + num_free; + host->sg_tablesize = QLOGICISP_MAX_SG(num_free); - hostdata = (struct isp1020_hostdata *) Cmnd->host->hostdata; - Cmnd->scsi_done = done; + LEAVE("isp1020_queuecommand"); - DEBUG(isp1020_print_scsi_cmd(Cmnd);) - - save_flags(flags); - cli(); - - hostdata->req_queue_out_ptr = inw(hostdata->io_base + MBOX4); - - if ((hostdata->req_queue_in_ptr + 1) % REQ_QUEUE_LEN == - hostdata->req_queue_out_ptr) { - restore_flags(flags); - printk("qlogicisp : request queue overflow\n"); - return 1; - } - - DEBUG(printk("qlogicisp : request queue depth %d\n", REQ_QUEUE_DEPTH())); + return 0; +} - cmd = (struct Command_Entry *) - &hostdata->req_queue[hostdata->req_queue_in_ptr][0]; - memset(cmd, 0, sizeof(struct Command_Entry)); +#define ASYNC_EVENT_INTERRUPT 0x01 - cmd->hdr.entry_type = ENTRY_COMMAND; - cmd->hdr.entry_cnt = 1; +void isp1020_intr_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + Scsi_Cmnd *Cmnd; + struct Status_Entry *sts; + struct Scsi_Host *host; + struct isp1020_hostdata *hostdata; + u_int in_ptr, out_ptr; + u_short status; + + ENTER_INTR("isp1020_intr_handler"); + + host = irq2host[irq]; + if (!host) { + printk("qlogicisp : unexpected interrupt on line %d\n", irq); + return; + } + hostdata = (struct isp1020_hostdata *) host->hostdata; + + DEBUG_INTR(printk("qlogicisp : interrupt on line %d\n", irq)); + + if (!(inw(host->io_port + PCI_INTF_STS) & 0x04)) { + /* spurious interrupts can happen legally */ + DEBUG_INTR(printk("qlogicisp: got spurious interrupt\n")); + return; + } + in_ptr = inw(host->io_port + MBOX5); + outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); + + if ((inw(host->io_port + PCI_SEMAPHORE) & ASYNC_EVENT_INTERRUPT)) { + status = inw(host->io_port + MBOX0); + + DEBUG_INTR(printk("qlogicisp : mbox completion status: %x\n", + status)); + + switch (status) { + case ASYNC_SCSI_BUS_RESET: + case EXECUTION_TIMEOUT_RESET: + hostdata->send_marker = 1; + break; + case INVALID_COMMAND: + case HOST_INTERFACE_ERROR: + case COMMAND_ERROR: + case COMMAND_PARAM_ERROR: + printk("qlogicisp : bad mailbox return status\n"); + break; + } + outw(0x0, host->io_port + PCI_SEMAPHORE); + } + out_ptr = hostdata->res_out_ptr; + + DEBUG_INTR(printk("qlogicisp : response queue update\n")); + DEBUG_INTR(printk("qlogicisp : response queue depth %d\n", + QUEUE_DEPTH(in_ptr, out_ptr))); + + while (out_ptr != in_ptr) { + sts = (struct Status_Entry *) &hostdata->res[out_ptr][0]; + out_ptr = (out_ptr + 1) & RES_QUEUE_LEN; + + Cmnd = (Scsi_Cmnd *) bus_to_virt(sts->handle); + + TRACE("done", out_ptr, Cmnd); + + if (sts->completion_status == CS_RESET_OCCURRED + || sts->completion_status == CS_ABORTED + || (sts->status_flags & STF_BUS_RESET)) + hostdata->send_marker = 1; + + if (sts->state_flags & SF_GOT_SENSE) + memcpy(Cmnd->sense_buffer, sts->req_sense_data, + sizeof(Cmnd->sense_buffer)); + + DEBUG_INTR(isp1020_print_status_entry(sts)); + + if (sts->hdr.entry_type == ENTRY_STATUS) + Cmnd->result = isp1020_return_status(sts); + else + Cmnd->result = DID_ERROR << 16; + + outw(out_ptr, host->io_port + MBOX5); + (*Cmnd->scsi_done)(Cmnd); + } + hostdata->res_out_ptr = out_ptr; - cmd->handle = (u_int) virt_to_bus(Cmnd); - cmd->target_lun = Cmnd->lun; - cmd->target_id = Cmnd->target; - cmd->cdb_length = Cmnd->cmd_len; - cmd->control_flags = CFLAG_READ | CFLAG_WRITE; - cmd->time_out = 30; + LEAVE_INTR("isp1020_intr_handler"); +} - for (i = 0; i < Cmnd->cmd_len; i++) - cmd->cdb[i] = Cmnd->cmnd[i]; - if (Cmnd->use_sg) { - cmd->segment_cnt = sg_count = Cmnd->use_sg; - sg = (struct scatterlist *) Cmnd->request_buffer; - iptr = (int *) &cmd->dataseg0.d_base; +static int isp1020_return_status(struct Status_Entry *sts) +{ + int host_status = DID_ERROR; +#if DEBUG_ISP1020_INTR + static char *reason[] = { + "DID_OK", + "DID_NO_CONNECT", + "DID_BUS_BUSY", + "DID_TIME_OUT", + "DID_BAD_TARGET", + "DID_ABORT", + "DID_PARITY", + "DID_ERROR", + "DID_RESET", + "DID_BAD_INTR" + }; +#endif /* DEBUG_ISP1020_INTR */ - for (i = 0; sg_count > 0; sg_count--, i++) { - *iptr++ = (int) virt_to_bus(sg[i].address); - *iptr++ = sg[i].length; - } - } - else { - cmd->dataseg0.d_base = (u_int) virt_to_bus(Cmnd->request_buffer); - cmd->dataseg0.d_count = (u_int) Cmnd->request_bufflen; - cmd->segment_cnt = 1; - } + ENTER("isp1020_return_status"); - hostdata->req_queue_in_ptr = (hostdata->req_queue_in_ptr + 1) - % REQ_QUEUE_LEN; + DEBUG(printk("qlogicisp : completion status = 0x%04x\n", + sts->completion_status)); - outw(hostdata->req_queue_in_ptr, hostdata->io_base + MBOX4); + switch(sts->completion_status) { + case CS_COMPLETE: + host_status = DID_OK; + break; + case CS_INCOMPLETE: + if (!(sts->state_flags & SF_GOT_BUS)) + host_status = DID_NO_CONNECT; + else if (!(sts->state_flags & SF_GOT_TARGET)) + host_status = DID_BAD_TARGET; + else if (!(sts->state_flags & SF_SENT_CDB)) + host_status = DID_ERROR; + else if (!(sts->state_flags & SF_TRANSFERRED_DATA)) + host_status = DID_ERROR; + else if (!(sts->state_flags & SF_GOT_STATUS)) + host_status = DID_ERROR; + else if (!(sts->state_flags & SF_GOT_SENSE)) + host_status = DID_ERROR; + break; + case CS_DMA_ERROR: + case CS_TRANSPORT_ERROR: + host_status = DID_ERROR; + break; + case CS_RESET_OCCURRED: + host_status = DID_RESET; + break; + case CS_ABORTED: + host_status = DID_ABORT; + break; + case CS_TIMEOUT: + host_status = DID_TIME_OUT; + break; + case CS_DATA_OVERRUN: + case CS_COMMAND_OVERRUN: + case CS_STATUS_OVERRUN: + case CS_BAD_MESSAGE: + case CS_NO_MESSAGE_OUT: + case CS_EXT_ID_FAILED: + case CS_IDE_MSG_FAILED: + case CS_ABORT_MSG_FAILED: + case CS_NOP_MSG_FAILED: + case CS_PARITY_ERROR_MSG_FAILED: + case CS_DEVICE_RESET_MSG_FAILED: + case CS_ID_MSG_FAILED: + case CS_UNEXP_BUS_FREE: + host_status = DID_ERROR; + break; + case CS_DATA_UNDERRUN: + host_status = DID_OK; + break; + default: + printk("qlogicisp : unknown completion status 0x%04x\n", + sts->completion_status); + host_status = DID_ERROR; + break; + } - restore_flags(flags); + DEBUG_INTR(printk("qlogicisp : host status (%s) scsi status %x\n", + reason[host_status], sts->scsi_status)); - LEAVE("isp1020_queuecommand"); + LEAVE("isp1020_return_status"); - return 0; + return (sts->scsi_status & STATUS_MASK) | (host_status << 16); } -#define RES_QUEUE_DEPTH() \ - (hostdata->res_queue_in_ptr >= hostdata->res_queue_out_ptr \ - ? hostdata->res_queue_in_ptr - hostdata->res_queue_out_ptr \ - : (RES_QUEUE_LEN - hostdata->res_queue_out_ptr) \ - + hostdata->res_queue_in_ptr) - - int isp1020_abort(Scsi_Cmnd *Cmnd) { - u_short param[6]; - struct isp1020_hostdata *hostdata; - int return_status = SCSI_ABORT_SUCCESS; - u_int cmdaddr = virt_to_bus(Cmnd); - - ENTER("isp1020_abort"); + u_short param[6]; + struct Scsi_Host *host; + struct isp1020_hostdata *hostdata; + int return_status = SCSI_ABORT_SUCCESS; + u_int cmdaddr = virt_to_bus(Cmnd); - hostdata = (struct isp1020_hostdata *) Cmnd->host->hostdata; + ENTER("isp1020_abort"); - isp1020_disable_irqs(hostdata); + host = Cmnd->host; + hostdata = (struct isp1020_hostdata *) host->hostdata; - DEBUG(printk("qlogicisp : response queue depth %d\n", RES_QUEUE_DEPTH())); + isp1020_disable_irqs(host); - param[0] = MBOX_ABORT; - param[1] = (((u_short) Cmnd->target) << 8) | Cmnd->lun; - param[2] = cmdaddr >> 16; - param[3] = cmdaddr & 0xffff; + param[0] = MBOX_ABORT; + param[1] = (((u_short) Cmnd->target) << 8) | Cmnd->lun; + param[2] = cmdaddr >> 16; + param[3] = cmdaddr & 0xffff; - isp1020_mbox_command(hostdata, param); + isp1020_mbox_command(host, param); - if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicisp : scsi abort failure: %x\n", param[0]); - return_status = SCSI_ABORT_ERROR; - } + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicisp : scsi abort failure: %x\n", param[0]); + return_status = SCSI_ABORT_ERROR; + } - isp1020_enable_irqs(hostdata); + isp1020_enable_irqs(host); - LEAVE("isp1020_abort"); + LEAVE("isp1020_abort"); - return return_status; + return return_status; } int isp1020_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags) { - u_short param[6]; - struct isp1020_hostdata *hostdata; - int return_status = SCSI_RESET_SUCCESS; + u_short param[6]; + struct Scsi_Host *host; + struct isp1020_hostdata *hostdata; + int return_status = SCSI_RESET_SUCCESS; - ENTER("isp1020_reset"); + ENTER("isp1020_reset"); - hostdata = (struct isp1020_hostdata *) Cmnd->host->hostdata; + host = Cmnd->host; + hostdata = (struct isp1020_hostdata *) host->hostdata; - param[0] = MBOX_BUS_RESET; - param[1] = hostdata->host_param.bus_reset_delay; + param[0] = MBOX_BUS_RESET; + param[1] = hostdata->host_param.bus_reset_delay; - isp1020_disable_irqs(hostdata); + isp1020_disable_irqs(host); - isp1020_mbox_command(hostdata, param); + isp1020_mbox_command(host, param); - if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicisp : scsi bus reset failure: %x\n", param[0]); - return_status = SCSI_RESET_ERROR; - } - - isp1020_enable_irqs(hostdata); + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicisp : scsi bus reset failure: %x\n", param[0]); + return_status = SCSI_RESET_ERROR; + } + + isp1020_enable_irqs(host); - LEAVE("isp1020_reset"); + LEAVE("isp1020_reset"); - return return_status;; + return return_status;; } int isp1020_biosparam(Disk *disk, kdev_t n, int ip[]) { - int size = disk->capacity; + int size = disk->capacity; - ENTER("isp1020_biosparam"); + ENTER("isp1020_biosparam"); - ip[0] = 64; - ip[1] = 32; - ip[2] = size >> 11; - if (ip[2] > 1024) { - ip[0] = 255; - ip[1] = 63; - ip[2] = size / (ip[0] * ip[1]); - if (ip[2] > 1023) - ip[2] = 1023; - } + ip[0] = 64; + ip[1] = 32; + ip[2] = size >> 11; + if (ip[2] > 1024) { + ip[0] = 255; + ip[1] = 63; + ip[2] = size / (ip[0] * ip[1]); + if (ip[2] > 1023) + ip[2] = 1023; + } - LEAVE("isp1020_biosparam"); + LEAVE("isp1020_biosparam"); - return 0; + return 0; } -int isp1020_reset_hardware(struct isp1020_hostdata *hostdata) +static int isp1020_reset_hardware(struct Scsi_Host *host) { - u_short param[6]; - int loop_count; + u_short param[6]; + int loop_count; - ENTER("isp1020_reset_hardware"); + ENTER("isp1020_reset_hardware"); - outw(ISP_RESET, hostdata->io_base + PCI_INTF_CTL); - outw(HCCR_RESET, hostdata->io_base + HOST_HCCR); - outw(HCCR_RELEASE, hostdata->io_base + HOST_HCCR); - outw(HCCR_BIOS_DISABLE, hostdata->io_base + HOST_HCCR); + outw(ISP_RESET, host->io_port + PCI_INTF_CTL); + outw(HCCR_RESET, host->io_port + HOST_HCCR); + outw(HCCR_RELEASE, host->io_port + HOST_HCCR); + outw(HCCR_BIOS_DISABLE, host->io_port + HOST_HCCR); - loop_count = DEFAULT_LOOP_COUNT; - while (--loop_count && inw(hostdata->io_base + HOST_HCCR) == RISC_BUSY) - barrier(); - if (!loop_count) - printk("qlogicisp: reset_hardware loop timeout\n"); + loop_count = DEFAULT_LOOP_COUNT; + while (--loop_count && inw(host->io_port + HOST_HCCR) == RISC_BUSY) + barrier(); + if (!loop_count) + printk("qlogicisp: reset_hardware loop timeout\n"); - outw(0, hostdata->io_base + ISP_CFG1); + outw(0, host->io_port + ISP_CFG1); #if DEBUG_ISP1020 - printk("qlogicisp : mbox 0 0x%04x \n", inw(hostdata->io_base + MBOX0)); - printk("qlogicisp : mbox 1 0x%04x \n", inw(hostdata->io_base + MBOX1)); - printk("qlogicisp : mbox 2 0x%04x \n", inw(hostdata->io_base + MBOX2)); - printk("qlogicisp : mbox 3 0x%04x \n", inw(hostdata->io_base + MBOX3)); - printk("qlogicisp : mbox 4 0x%04x \n", inw(hostdata->io_base + MBOX4)); - printk("qlogicisp : mbox 5 0x%04x \n", inw(hostdata->io_base + MBOX5)); + printk("qlogicisp : mbox 0 0x%04x \n", inw(host->io_port + MBOX0)); + printk("qlogicisp : mbox 1 0x%04x \n", inw(host->io_port + MBOX1)); + printk("qlogicisp : mbox 2 0x%04x \n", inw(host->io_port + MBOX2)); + printk("qlogicisp : mbox 3 0x%04x \n", inw(host->io_port + MBOX3)); + printk("qlogicisp : mbox 4 0x%04x \n", inw(host->io_port + MBOX4)); + printk("qlogicisp : mbox 5 0x%04x \n", inw(host->io_port + MBOX5)); #endif /* DEBUG_ISP1020 */ - DEBUG(printk("qlogicisp : loading risc ram\n");) + DEBUG(printk("qlogicisp : loading risc ram\n")); #if RELOAD_FIRMWARE - { int i; - for (i = 0; i < risc_code_length01; i++) { - param[0] = MBOX_WRITE_RAM_WORD; - param[1] = risc_code_addr01 + i; - param[2] = risc_code01[i]; - - isp1020_mbox_command(hostdata, param); - - if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicisp : firmware load failure\n"); - return 1; - } - } - } + { + int i; + for (i = 0; i < risc_code_length01; i++) { + param[0] = MBOX_WRITE_RAM_WORD; + param[1] = risc_code_addr01 + i; + param[2] = risc_code01[i]; + + isp1020_mbox_command(host, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicisp : firmware load failure\n"); + return 1; + } + } + } #endif /* RELOAD_FIRMWARE */ - DEBUG(printk("qlogicisp : verifying checksum\n");) + DEBUG(printk("qlogicisp : verifying checksum\n")); - param[0] = MBOX_VERIFY_CHECKSUM; - param[1] = risc_code_addr01; + param[0] = MBOX_VERIFY_CHECKSUM; + param[1] = risc_code_addr01; - isp1020_mbox_command(hostdata, param); + isp1020_mbox_command(host, param); - if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicisp : ram checksum failure\n"); - return 1; - } + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicisp : ram checksum failure\n"); + return 1; + } - DEBUG(printk("qlogicisp : executing firmware\n");) + DEBUG(printk("qlogicisp : executing firmware\n")); - param[0] = MBOX_EXEC_FIRMWARE; - param[1] = risc_code_addr01; + param[0] = MBOX_EXEC_FIRMWARE; + param[1] = risc_code_addr01; - isp1020_mbox_command(hostdata, param); + isp1020_mbox_command(host, param); - param[0] = MBOX_ABOUT_FIRMWARE; + param[0] = MBOX_ABOUT_FIRMWARE; - isp1020_mbox_command(hostdata, param); + isp1020_mbox_command(host, param); - if (param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicisp : about firmware failure\n"); - return 1; - } + if (param[0] != MBOX_COMMAND_COMPLETE) { + printk("qlogicisp : about firmware failure\n"); + return 1; + } - DEBUG(printk("qlogicisp : firmware major revision %d\n", param[1]);) - DEBUG(printk("qlogicisp : firmware minor revision %d\n", param[2]);) + DEBUG(printk("qlogicisp : firmware major revision %d\n", param[1])); + DEBUG(printk("qlogicisp : firmware minor revision %d\n", param[2])); - LEAVE("isp1020_reset_hardware"); + LEAVE("isp1020_reset_hardware"); - return 0; + return 0; } -int isp1020_init(struct Scsi_Host *sh) +static int isp1020_init(struct Scsi_Host *sh) { - u_int io_base; - struct isp1020_hostdata *hostdata; - u_char bus, device_fn, revision, irq; - u_short vendor_id, device_id, command; + u_int io_base; + struct isp1020_hostdata *hostdata; + u_char bus, device_fn, revision, irq; + u_short vendor_id, device_id, command; - ENTER("isp1020_init"); + ENTER("isp1020_init"); - hostdata = (struct isp1020_hostdata *) sh->hostdata; - bus = hostdata->bus; - device_fn = hostdata->device_fn; + hostdata = (struct isp1020_hostdata *) sh->hostdata; + bus = hostdata->bus; + device_fn = hostdata->device_fn; - if (pcibios_read_config_word(bus, device_fn, PCI_VENDOR_ID, &vendor_id) + if (pcibios_read_config_word(bus, device_fn, PCI_VENDOR_ID, &vendor_id) || pcibios_read_config_word(bus, device_fn, - PCI_DEVICE_ID, &device_id) + PCI_DEVICE_ID, &device_id) || pcibios_read_config_word(bus, device_fn, - PCI_COMMAND, &command) + PCI_COMMAND, &command) || pcibios_read_config_dword(bus, device_fn, - PCI_BASE_ADDRESS_0, &io_base) + PCI_BASE_ADDRESS_0, &io_base) || pcibios_read_config_byte(bus, device_fn, - PCI_CLASS_REVISION, &revision) + PCI_CLASS_REVISION, &revision) || pcibios_read_config_byte(bus, device_fn, - PCI_INTERRUPT_LINE, &irq)) { - printk("qlogicisp : error reading PCI configuration\n"); - return 1; - } - - if (vendor_id != PCI_VENDOR_ID_QLOGIC) { - printk("qlogicisp : 0x%04x is not QLogic vendor ID\n", vendor_id); - return 1; - } - - if (device_id != PCI_DEVICE_ID_QLOGIC_ISP1020) { - printk("qlogicisp : 0x%04x does not match ISP1020 device id\n", - device_id); - return 1; - } - - if (command & PCI_COMMAND_IO && (io_base & 3) == 1) - io_base &= PCI_BASE_ADDRESS_IO_MASK; - else { - printk("qlogicisp : i/o mapping is disabled\n"); - return 1; - } - - if (!(command & PCI_COMMAND_MASTER)) { - printk("qlogicisp : bus mastering is disabled\n"); - return 1; - } - - if (revision != ISP1020_REV_ID) - printk("qlogicisp : new isp1020 revision ID (%d)\n", revision); - - if (inw(io_base + PCI_ID_LOW) != PCI_VENDOR_ID_QLOGIC - || inw(io_base + PCI_ID_HIGH) != PCI_DEVICE_ID_QLOGIC_ISP1020) { - printk("qlogicisp : can't decode i/o address space\n"); - return 1; - } - - hostdata->io_base = io_base; - hostdata->revision = revision; - hostdata->irq = irq; - - LEAVE("isp1020_init"); - - return 0; -} - - -int isp1020_get_defaults(struct isp1020_hostdata *hostdata) -{ - int i; - u_short value; - - ENTER("isp1020_get_defaults"); - - if (!isp1020_verify_nvram(hostdata)) { - printk("qlogicisp : nvram checksum failure\n"); - printk("qlogicisp : attempting to use default parameters\n"); - return isp1020_set_defaults(hostdata); - } - - value = isp1020_read_nvram_word(hostdata, 2); - hostdata->host_param.fifo_threshold = (value >> 8) & 0x03; - hostdata->host_param.host_adapter_enable = (value >> 11) & 0x01; - hostdata->host_param.initiator_scsi_id = (value >> 12) & 0x0f; - - value = isp1020_read_nvram_word(hostdata, 3); - hostdata->host_param.bus_reset_delay = value & 0xff; - hostdata->host_param.retry_count = value >> 8; - - value = isp1020_read_nvram_word(hostdata, 4); - hostdata->host_param.retry_delay = value & 0xff; - hostdata->host_param.async_data_setup_time = (value >> 8) & 0x0f; - hostdata->host_param.req_ack_active_negation = (value >> 12) & 0x01; - hostdata->host_param.data_line_active_negation = (value >> 13) & 0x01; - hostdata->host_param.data_dma_burst_enable = (value >> 14) & 0x01; - hostdata->host_param.command_dma_burst_enable = (value >> 15); + PCI_INTERRUPT_LINE, &irq)) + { + printk("qlogicisp : error reading PCI configuration\n"); + return 1; + } + + if (vendor_id != PCI_VENDOR_ID_QLOGIC) { + printk("qlogicisp : 0x%04x is not QLogic vendor ID\n", + vendor_id); + return 1; + } + + if (device_id != PCI_DEVICE_ID_QLOGIC_ISP1020) { + printk("qlogicisp : 0x%04x does not match ISP1020 device id\n", + device_id); + return 1; + } + + if (command & PCI_COMMAND_IO && (io_base & 3) == 1) + io_base &= PCI_BASE_ADDRESS_IO_MASK; + else { + printk("qlogicisp : i/o mapping is disabled\n"); + return 1; + } + + if (!(command & PCI_COMMAND_MASTER)) { + printk("qlogicisp : bus mastering is disabled\n"); + return 1; + } + + if (revision != ISP1020_REV_ID) + printk("qlogicisp : new isp1020 revision ID (%d)\n", revision); + + if (inw(io_base + PCI_ID_LOW) != PCI_VENDOR_ID_QLOGIC + || inw(io_base + PCI_ID_HIGH) != PCI_DEVICE_ID_QLOGIC_ISP1020) + { + printk("qlogicisp : can't decode i/o address space\n"); + return 1; + } - value = isp1020_read_nvram_word(hostdata, 5); - hostdata->host_param.tag_aging = value & 0xff; + hostdata->revision = revision; - value = isp1020_read_nvram_word(hostdata, 6); - hostdata->host_param.selection_timeout = value & 0xffff; + sh->irq = irq; + sh->io_port = io_base; - value = isp1020_read_nvram_word(hostdata, 7); - hostdata->host_param.max_queue_depth = value & 0xffff; + LEAVE("isp1020_init"); -#if DEBUG_ISP1020_SETUP - printk("qlogicisp : fifo threshold=%d\n", - hostdata->host_param.fifo_threshold); - printk("qlogicisp : initiator scsi id=%d\n", - hostdata->host_param.initiator_scsi_id); - printk("qlogicisp : bus reset delay=%d\n", - hostdata->host_param.bus_reset_delay); - printk("qlogicisp : retry count=%d\n", - hostdata->host_param.retry_count); - printk("qlogicisp : retry delay=%d\n", - hostdata->host_param.retry_delay); - printk("qlogicisp : async data setup time=%d\n", - hostdata->host_param.async_data_setup_time); - printk("qlogicisp : req/ack active negation=%d\n", - hostdata->host_param.req_ack_active_negation); - printk("qlogicisp : data line active negation=%d\n", - hostdata->host_param.data_line_active_negation); - printk("qlogicisp : data DMA burst enable=%d\n", - hostdata->host_param.data_dma_burst_enable); - printk("qlogicisp : command DMA burst enable=%d\n", - hostdata->host_param.command_dma_burst_enable); - printk("qlogicisp : tag age limit=%d\n", - hostdata->host_param.tag_aging); - printk("qlogicisp : selection timeout limit=%d\n", - hostdata->host_param.selection_timeout); - printk("qlogicisp : max queue depth=%d\n", - hostdata->host_param.max_queue_depth); -#endif /* DEBUG_ISP1020_SETUP */ - - for (i = 0; i < MAX_TARGETS; i++) { - - value = isp1020_read_nvram_word(hostdata, 14 + i * 3); - hostdata->dev_param[i].device_flags = value & 0xff; - hostdata->dev_param[i].execution_throttle = value >> 8; - - value = isp1020_read_nvram_word(hostdata, 15 + i * 3); - hostdata->dev_param[i].synchronous_period = value & 0xff; - hostdata->dev_param[i].synchronous_offset = (value >> 8) & 0x0f; - hostdata->dev_param[i].device_enable = (value >> 12) & 0x01; - -#if DEBUG_ISP1020_SETUP - printk("qlogicisp : target 0x%02x\n", i); - printk("qlogicisp : device flags=0x%02x\n", - hostdata->dev_param[i].device_flags); - printk("qlogicisp : execution throttle=%d\n", - hostdata->dev_param[i].execution_throttle); - printk("qlogicisp : synchronous period=%d\n", - hostdata->dev_param[i].synchronous_period); - printk("qlogicisp : synchronous offset=%d\n", - hostdata->dev_param[i].synchronous_offset); - printk("qlogicisp : device enable=%d\n", - hostdata->dev_param[i].device_enable); -#endif /* DEBUG_ISP1020_SETUP */ - } - - LEAVE("isp1020_get_defaults"); - - return 0; + return 0; } -int isp1020_set_defaults(struct isp1020_hostdata *hostdata) -{ - int i; - - ENTER("isp1020_set_defaults"); - - hostdata->host_param.fifo_threshold = 2; - hostdata->host_param.host_adapter_enable = 1; - hostdata->host_param.initiator_scsi_id = 7; - hostdata->host_param.bus_reset_delay = 3; - hostdata->host_param.retry_count = 0; - hostdata->host_param.retry_delay = 1; - hostdata->host_param.async_data_setup_time = 6; - hostdata->host_param.req_ack_active_negation = 1; - hostdata->host_param.data_line_active_negation = 1; - hostdata->host_param.data_dma_burst_enable = 1; - hostdata->host_param.command_dma_burst_enable = 1; - hostdata->host_param.tag_aging = 8; - hostdata->host_param.selection_timeout = 250; - hostdata->host_param.max_queue_depth = 256; - - for (i = 0; i < MAX_TARGETS; i++) { - hostdata->dev_param[i].device_flags = 0xfd; - hostdata->dev_param[i].execution_throttle = 16; - hostdata->dev_param[i].synchronous_period = 25; - hostdata->dev_param[i].synchronous_offset = 12; - hostdata->dev_param[i].device_enable = 1; - } - - LEAVE("isp1020_set_defaults"); - - return 0; -} - +#if USE_NVRAM_DEFAULTS -int isp1020_load_parameters(struct isp1020_hostdata *hostdata) +static int isp1020_get_defaults(struct Scsi_Host *host) { - int i, k; - u_int queue_addr; - u_short param[6]; - u_short isp_cfg1; - unsigned long flags; - - ENTER("isp1020_load_parameters"); - - save_flags(flags); - cli(); - - outw(hostdata->host_param.fifo_threshold, hostdata->io_base + ISP_CFG1); - - param[0] = MBOX_SET_INIT_SCSI_ID; - param[1] = hostdata->host_param.initiator_scsi_id; + int i; + u_short value; + struct isp1020_hostdata *hostdata = + (struct isp1020_hostdata *) host->hostdata; + + ENTER("isp1020_get_defaults"); + + if (!isp1020_verify_nvram(host)) { + printk("qlogicisp : nvram checksum failure\n"); + printk("qlogicisp : attempting to use default parameters\n"); + return isp1020_set_defaults(host); + } + + value = isp1020_read_nvram_word(host, 2); + hostdata->host_param.fifo_threshold = (value >> 8) & 0x03; + hostdata->host_param.host_adapter_enable = (value >> 11) & 0x01; + hostdata->host_param.initiator_scsi_id = (value >> 12) & 0x0f; + + value = isp1020_read_nvram_word(host, 3); + hostdata->host_param.bus_reset_delay = value & 0xff; + hostdata->host_param.retry_count = value >> 8; + + value = isp1020_read_nvram_word(host, 4); + hostdata->host_param.retry_delay = value & 0xff; + hostdata->host_param.async_data_setup_time = (value >> 8) & 0x0f; + hostdata->host_param.req_ack_active_negation = (value >> 12) & 0x01; + hostdata->host_param.data_line_active_negation = (value >> 13) & 0x01; + hostdata->host_param.data_dma_burst_enable = (value >> 14) & 0x01; + hostdata->host_param.command_dma_burst_enable = (value >> 15); - isp1020_mbox_command(hostdata, param); + value = isp1020_read_nvram_word(host, 5); + hostdata->host_param.tag_aging = value & 0xff; - if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); - printk("qlogicisp : set initiator id failure\n"); - return 1; - } - - param[0] = MBOX_SET_RETRY_COUNT; - param[1] = hostdata->host_param.retry_count; - param[2] = hostdata->host_param.retry_delay; - - isp1020_mbox_command(hostdata, param); - - if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); - printk("qlogicisp : set retry count failure\n"); - return 1; - } + value = isp1020_read_nvram_word(host, 6); + hostdata->host_param.selection_timeout = value & 0xffff; - param[0] = MBOX_SET_ASYNC_DATA_SETUP_TIME; - param[1] = hostdata->host_param.async_data_setup_time; + value = isp1020_read_nvram_word(host, 7); + hostdata->host_param.max_queue_depth = value & 0xffff; - isp1020_mbox_command(hostdata, param); - - if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); - printk("qlogicisp : async data setup time failure\n"); - return 1; - } - - param[0] = MBOX_SET_ACTIVE_NEG_STATE; - param[1] = (hostdata->host_param.req_ack_active_negation << 4) - | (hostdata->host_param.data_line_active_negation << 5); - - isp1020_mbox_command(hostdata, param); - - if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); - printk("qlogicisp : set active negation state failure\n"); - return 1; - } - - param[0] = MBOX_SET_PCI_CONTROL_PARAMS; - param[1] = hostdata->host_param.data_dma_burst_enable << 1; - param[2] = hostdata->host_param.command_dma_burst_enable << 1; - - isp1020_mbox_command(hostdata, param); - - if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); - printk("qlogicisp : set pci control parameter failure\n"); - return 1; - } - - isp_cfg1 = inw(hostdata->io_base + ISP_CFG1); - - if (hostdata->host_param.data_dma_burst_enable - || hostdata->host_param.command_dma_burst_enable) - isp_cfg1 |= 0x0004; - else - isp_cfg1 &= 0xfffb; - - outw(isp_cfg1, hostdata->io_base + ISP_CFG1); - - param[0] = MBOX_SET_TAG_AGE_LIMIT; - param[1] = hostdata->host_param.tag_aging; - - isp1020_mbox_command(hostdata, param); - - if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); - printk("qlogicisp : set tag age limit failure\n"); - return 1; - } - - param[0] = MBOX_SET_SELECT_TIMEOUT; - param[1] = hostdata->host_param.selection_timeout; - - isp1020_mbox_command(hostdata, param); - - if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); - printk("qlogicisp : set selection timeout failure\n"); - return 1; - } - - for (i = 0; i < MAX_TARGETS; i++) { - - if (!hostdata->dev_param[i].device_enable) - continue; - - param[0] = MBOX_SET_TARGET_PARAMS; - param[1] = i << 8; - param[2] = hostdata->dev_param[i].device_flags << 8; - param[3] = (hostdata->dev_param[i].synchronous_offset << 8) - | hostdata->dev_param[i].synchronous_period; - - isp1020_mbox_command(hostdata, param); - - if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); - printk("qlogicisp : set target parameter failure\n"); - return 1; - } - - for (k = 0; k < MAX_LUNS; k++) { - - param[0] = MBOX_SET_DEV_QUEUE_PARAMS; - param[1] = (i << 8) | k; - param[2] = hostdata->host_param.max_queue_depth; - param[3] = hostdata->dev_param[i].execution_throttle; - - isp1020_mbox_command(hostdata, param); - - if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); - printk("qlogicisp : set device queue parameter failure\n"); - return 1; - } - } - } - - queue_addr = (u_int) virt_to_bus(&hostdata->res_queue[0][0]); - - param[0] = MBOX_INIT_RES_QUEUE; - param[1] = RES_QUEUE_LEN; - param[2] = (u_short) (queue_addr >> 16); - param[3] = (u_short) (queue_addr & 0xffff); - param[4] = 0; - param[5] = 0; +#if DEBUG_ISP1020_SETUP + printk("qlogicisp : fifo threshold=%d\n", + hostdata->host_param.fifo_threshold); + printk("qlogicisp : initiator scsi id=%d\n", + hostdata->host_param.initiator_scsi_id); + printk("qlogicisp : bus reset delay=%d\n", + hostdata->host_param.bus_reset_delay); + printk("qlogicisp : retry count=%d\n", + hostdata->host_param.retry_count); + printk("qlogicisp : retry delay=%d\n", + hostdata->host_param.retry_delay); + printk("qlogicisp : async data setup time=%d\n", + hostdata->host_param.async_data_setup_time); + printk("qlogicisp : req/ack active negation=%d\n", + hostdata->host_param.req_ack_active_negation); + printk("qlogicisp : data line active negation=%d\n", + hostdata->host_param.data_line_active_negation); + printk("qlogicisp : data DMA burst enable=%d\n", + hostdata->host_param.data_dma_burst_enable); + printk("qlogicisp : command DMA burst enable=%d\n", + hostdata->host_param.command_dma_burst_enable); + printk("qlogicisp : tag age limit=%d\n", + hostdata->host_param.tag_aging); + printk("qlogicisp : selection timeout limit=%d\n", + hostdata->host_param.selection_timeout); + printk("qlogicisp : max queue depth=%d\n", + hostdata->host_param.max_queue_depth); +#endif /* DEBUG_ISP1020_SETUP */ - isp1020_mbox_command(hostdata, param); + for (i = 0; i < MAX_TARGETS; i++) { - if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); - printk("qlogicisp : set response queue failure\n"); - return 1; - } + value = isp1020_read_nvram_word(host, 14 + i * 3); + hostdata->dev_param[i].device_flags = value & 0xff; + hostdata->dev_param[i].execution_throttle = value >> 8; + + value = isp1020_read_nvram_word(host, 15 + i * 3); + hostdata->dev_param[i].synchronous_period = value & 0xff; + hostdata->dev_param[i].synchronous_offset = (value >> 8) & 0x0f; + hostdata->dev_param[i].device_enable = (value >> 12) & 0x01; - queue_addr = (u_int) virt_to_bus(&hostdata->req_queue[0][0]); +#if DEBUG_ISP1020_SETUP + printk("qlogicisp : target 0x%02x\n", i); + printk("qlogicisp : device flags=0x%02x\n", + hostdata->dev_param[i].device_flags); + printk("qlogicisp : execution throttle=%d\n", + hostdata->dev_param[i].execution_throttle); + printk("qlogicisp : synchronous period=%d\n", + hostdata->dev_param[i].synchronous_period); + printk("qlogicisp : synchronous offset=%d\n", + hostdata->dev_param[i].synchronous_offset); + printk("qlogicisp : device enable=%d\n", + hostdata->dev_param[i].device_enable); +#endif /* DEBUG_ISP1020_SETUP */ + } - param[0] = MBOX_INIT_REQ_QUEUE; - param[1] = REQ_QUEUE_LEN; - param[2] = (u_short) (queue_addr >> 16); - param[3] = (u_short) (queue_addr & 0xffff); - param[4] = 0; + LEAVE("isp1020_get_defaults"); - isp1020_mbox_command(hostdata, param); + return 0; +} - if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); - printk("qlogicisp : set request queue failure\n"); - return 1; - } - restore_flags(flags); +#define ISP1020_NVRAM_LEN 0x40 +#define ISP1020_NVRAM_SIG1 0x5349 +#define ISP1020_NVRAM_SIG2 0x2050 - LEAVE("isp1020_load_parameters"); +static int isp1020_verify_nvram(struct Scsi_Host *host) +{ + int i; + u_short value; + u_char checksum = 0; + + for (i = 0; i < ISP1020_NVRAM_LEN; i++) { + value = isp1020_read_nvram_word(host, i); + + switch (i) { + case 0: + if (value != ISP1020_NVRAM_SIG1) return 0; + break; + case 1: + if (value != ISP1020_NVRAM_SIG2) return 0; + break; + case 2: + if ((value & 0xff) != 0x02) return 0; + break; + } + checksum += value & 0xff; + checksum += value >> 8; + } - return 0; + return (checksum == 0); } +#define NVRAM_DELAY() udelay(2) /* 2 microsecond delay */ -/* - * currently, this is only called during initialization or abort/reset, - * at which times interrupts are disabled, so polling is OK, I guess... - */ -int isp1020_mbox_command(struct isp1020_hostdata *hostdata, u_short param[]) + +u_short isp1020_read_nvram_word(struct Scsi_Host *host, u_short byte) { - int loop_count; + int i; + u_short value, output, input; - if (mbox_param[param[0]] == 0) - return 1; + byte &= 0x3f; byte |= 0x0180; - loop_count = DEFAULT_LOOP_COUNT; - while (--loop_count && inw(hostdata->io_base + HOST_HCCR) & 0x0080) - barrier(); - if (!loop_count) - printk("qlogicisp: mbox_command loop timeout #1\n"); - - switch(mbox_param[param[0]] >> 4) { - case 6: outw(param[5], hostdata->io_base + MBOX5); - case 5: outw(param[4], hostdata->io_base + MBOX4); - case 4: outw(param[3], hostdata->io_base + MBOX3); - case 3: outw(param[2], hostdata->io_base + MBOX2); - case 2: outw(param[1], hostdata->io_base + MBOX1); - case 1: outw(param[0], hostdata->io_base + MBOX0); - } - - outw(0x0, hostdata->io_base + PCI_SEMAPHORE); - outw(HCCR_CLEAR_RISC_INTR, hostdata->io_base + HOST_HCCR); - outw(HCCR_SET_HOST_INTR, hostdata->io_base + HOST_HCCR); - - loop_count = DEFAULT_LOOP_COUNT; - while (--loop_count && !(inw(hostdata->io_base + PCI_INTF_STS) & 0x04)) - barrier(); - if (!loop_count) - printk("qlogicisp: mbox_command loop timeout #2\n"); - - loop_count = DEFAULT_LOOP_COUNT; - while (--loop_count && inw(hostdata->io_base + MBOX0) == 0x04) - barrier(); - if (!loop_count) - printk("qlogicisp: mbox_command loop timeout #3\n"); - - switch(mbox_param[param[0]] & 0xf) { - case 6: param[5] = inw(hostdata->io_base + MBOX5); - case 5: param[4] = inw(hostdata->io_base + MBOX4); - case 4: param[3] = inw(hostdata->io_base + MBOX3); - case 3: param[2] = inw(hostdata->io_base + MBOX2); - case 2: param[1] = inw(hostdata->io_base + MBOX1); - case 1: param[0] = inw(hostdata->io_base + MBOX0); - } + for (i = 8; i >= 0; i--) { + output = ((byte >> i) & 0x1) ? 0x4 : 0x0; + outw(output | 0x2, host->io_port + PCI_NVRAM); NVRAM_DELAY(); + outw(output | 0x3, host->io_port + PCI_NVRAM); NVRAM_DELAY(); + outw(output | 0x2, host->io_port + PCI_NVRAM); NVRAM_DELAY(); + } + + for (i = 0xf, value = 0; i >= 0; i--) { + value <<= 1; + outw(0x3, host->io_port + PCI_NVRAM); NVRAM_DELAY(); + input = inw(host->io_port + PCI_NVRAM); NVRAM_DELAY(); + outw(0x2, host->io_port + PCI_NVRAM); NVRAM_DELAY(); + if (input & 0x8) value |= 1; + } - outw(0x0, hostdata->io_base + PCI_SEMAPHORE); - outw(HCCR_CLEAR_RISC_INTR, hostdata->io_base + HOST_HCCR); + outw(0x0, host->io_port + PCI_NVRAM); NVRAM_DELAY(); - return 0; + return value; } +#endif /* USE_NVRAM_DEFAULTS */ -#define MAILBOX_INTERRUPT 0x01 -void isp1020_intr_handler(int irq, void *dev_id, struct pt_regs *regs) +static int isp1020_set_defaults(struct Scsi_Host *host) { - Scsi_Cmnd *Cmnd; - struct Status_Entry *sts; - struct Marker_Entry *marker; - u_short status, add_marker = 0; - struct isp1020_hostdata *hostdata; - int loop_count; - - ENTER_INTR("isp1020_intr_handler"); - - if ((hostdata = irq2host[irq]) == NULL) { - printk("qlogicisp : unexpected interrupt on line %d\n", irq); - return; - } - - DEBUG_INTR(printk("qlogicisp : interrupt on line %d\n", irq);) - - loop_count = DEFAULT_LOOP_COUNT; - while (--loop_count && !(inw(hostdata->io_base + PCI_INTF_STS) & 0x04)) - barrier(); - if (!loop_count) - printk("qlogicisp: intr_handler loop timeout\n"); - - status = inw(hostdata->io_base + PCI_SEMAPHORE); - - if ((status & MAILBOX_INTERRUPT) == 0) { + struct isp1020_hostdata *hostdata = + (struct isp1020_hostdata *) host->hostdata; + int i; + + ENTER("isp1020_set_defaults"); + + hostdata->host_param.fifo_threshold = 2; + hostdata->host_param.host_adapter_enable = 1; + hostdata->host_param.initiator_scsi_id = 7; + hostdata->host_param.bus_reset_delay = 3; + hostdata->host_param.retry_count = 0; + hostdata->host_param.retry_delay = 1; + hostdata->host_param.async_data_setup_time = 6; + hostdata->host_param.req_ack_active_negation = 1; + hostdata->host_param.data_line_active_negation = 1; + hostdata->host_param.data_dma_burst_enable = 1; + hostdata->host_param.command_dma_burst_enable = 1; + hostdata->host_param.tag_aging = 8; + hostdata->host_param.selection_timeout = 250; + hostdata->host_param.max_queue_depth = 256; + + for (i = 0; i < MAX_TARGETS; i++) { + hostdata->dev_param[i].device_flags = 0xfd; + hostdata->dev_param[i].execution_throttle = 16; + hostdata->dev_param[i].synchronous_period = 25; + hostdata->dev_param[i].synchronous_offset = 12; + hostdata->dev_param[i].device_enable = 1; + } + + LEAVE("isp1020_set_defaults"); + + return 0; +} - hostdata->res_queue_in_ptr = inw(hostdata->io_base + MBOX5); - outw(HCCR_CLEAR_RISC_INTR, hostdata->io_base + HOST_HCCR); - DEBUG_INTR(printk("qlogicisp : response queue update\n");) - DEBUG_INTR(printk("qlogicisp : response queue depth %d\n", - RES_QUEUE_DEPTH());) +static int isp1020_load_parameters(struct Scsi_Host *host) +{ + int i, k; + u_int queue_addr; + u_short param[6]; + u_short isp_cfg1; + unsigned long flags; + struct isp1020_hostdata *hostdata = + (struct isp1020_hostdata *) host->hostdata; - while (hostdata->res_queue_out_ptr != hostdata->res_queue_in_ptr) { + ENTER("isp1020_load_parameters"); - sts = (struct Status_Entry *) - &hostdata->res_queue[hostdata->res_queue_out_ptr][0]; + save_flags(flags); + cli(); - Cmnd = (Scsi_Cmnd *) bus_to_virt(sts->handle); + outw(hostdata->host_param.fifo_threshold, host->io_port + ISP_CFG1); - if (sts->completion_status == CS_RESET_OCCURRED - || sts->completion_status == CS_ABORTED - || (sts->status_flags & STF_BUS_RESET)) - add_marker++; + param[0] = MBOX_SET_INIT_SCSI_ID; + param[1] = hostdata->host_param.initiator_scsi_id; - if (sts->state_flags & SF_GOT_SENSE) - memcpy(Cmnd->sense_buffer, sts->req_sense_data, - sizeof(Cmnd->sense_buffer)); + isp1020_mbox_command(host, param); - DEBUG_INTR(isp1020_print_status_entry(sts);) + if (param[0] != MBOX_COMMAND_COMPLETE) { + restore_flags(flags); + printk("qlogicisp : set initiator id failure\n"); + return 1; + } - if (sts->hdr.entry_type == ENTRY_STATUS) - Cmnd->result = isp1020_return_status(sts); - else - Cmnd->result = DID_ERROR << 16; + param[0] = MBOX_SET_RETRY_COUNT; + param[1] = hostdata->host_param.retry_count; + param[2] = hostdata->host_param.retry_delay; - hostdata->res_queue_out_ptr = (hostdata->res_queue_out_ptr + 1) - % RES_QUEUE_LEN; + isp1020_mbox_command(host, param); - outw(hostdata->res_queue_out_ptr, hostdata->io_base + MBOX5); + if (param[0] != MBOX_COMMAND_COMPLETE) { + restore_flags(flags); + printk("qlogicisp : set retry count failure\n"); + return 1; + } - (Cmnd->scsi_done)(Cmnd); - } - } - else { + param[0] = MBOX_SET_ASYNC_DATA_SETUP_TIME; + param[1] = hostdata->host_param.async_data_setup_time; - status = inw(hostdata->io_base + MBOX0); + isp1020_mbox_command(host, param); - DEBUG_INTR(printk("qlogicisp : mbox completion status: %x\n", status);) + if (param[0] != MBOX_COMMAND_COMPLETE) { + restore_flags(flags); + printk("qlogicisp : async data setup time failure\n"); + return 1; + } - switch (status) { - case ASYNC_SCSI_BUS_RESET: - case EXECUTION_TIMEOUT_RESET: - add_marker++; - break; - case INVALID_COMMAND: - case HOST_INTERFACE_ERROR: - case COMMAND_ERROR: - case COMMAND_PARAM_ERROR: - printk("qlogicisp : bad mailbox return status\n"); - break; - } + param[0] = MBOX_SET_ACTIVE_NEG_STATE; + param[1] = (hostdata->host_param.req_ack_active_negation << 4) + | (hostdata->host_param.data_line_active_negation << 5); - outw(0x0, hostdata->io_base + PCI_SEMAPHORE); - outw(HCCR_CLEAR_RISC_INTR, hostdata->io_base + HOST_HCCR); - } + isp1020_mbox_command(host, param); - if (add_marker) { -#if 0 - unsigned long flags; + if (param[0] != MBOX_COMMAND_COMPLETE) { + restore_flags(flags); + printk("qlogicisp : set active negation state failure\n"); + return 1; + } - save_flags(flags); - cli(); -#endif + param[0] = MBOX_SET_PCI_CONTROL_PARAMS; + param[1] = hostdata->host_param.data_dma_burst_enable << 1; + param[2] = hostdata->host_param.command_dma_burst_enable << 1; - DEBUG_INTR(printk("qlogicisp : adding marker entry\n");) + isp1020_mbox_command(host, param); - if ((hostdata->req_queue_in_ptr + 1) % REQ_QUEUE_LEN - == hostdata->req_queue_out_ptr) { -#if 0 - restore_flags(flags); -#endif - printk("qlogicisp : request queue overflow\n"); - return; - } + if (param[0] != MBOX_COMMAND_COMPLETE) { + restore_flags(flags); + printk("qlogicisp : set pci control parameter failure\n"); + return 1; + } - marker = (struct Marker_Entry *) - &hostdata->req_queue[hostdata->req_queue_in_ptr][0]; + isp_cfg1 = inw(host->io_port + ISP_CFG1); - memset(marker, 0, sizeof(struct Marker_Entry)); - - marker->hdr.entry_type = ENTRY_MARKER; - marker->hdr.entry_cnt = 1; - marker->modifier = SYNC_ALL; - - hostdata->req_queue_in_ptr = (hostdata->req_queue_in_ptr + 1) - % REQ_QUEUE_LEN; - - outw(hostdata->req_queue_in_ptr, hostdata->io_base + MBOX4); + if (hostdata->host_param.data_dma_burst_enable + || hostdata->host_param.command_dma_burst_enable) + isp_cfg1 |= 0x0004; + else + isp_cfg1 &= 0xfffb; + + outw(isp_cfg1, host->io_port + ISP_CFG1); + + param[0] = MBOX_SET_TAG_AGE_LIMIT; + param[1] = hostdata->host_param.tag_aging; + + isp1020_mbox_command(host, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + restore_flags(flags); + printk("qlogicisp : set tag age limit failure\n"); + return 1; + } + + param[0] = MBOX_SET_SELECT_TIMEOUT; + param[1] = hostdata->host_param.selection_timeout; + + isp1020_mbox_command(host, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + restore_flags(flags); + printk("qlogicisp : set selection timeout failure\n"); + return 1; + } + + for (i = 0; i < MAX_TARGETS; i++) { + + if (!hostdata->dev_param[i].device_enable) + continue; + + param[0] = MBOX_SET_TARGET_PARAMS; + param[1] = i << 8; + param[2] = hostdata->dev_param[i].device_flags << 8; + param[3] = (hostdata->dev_param[i].synchronous_offset << 8) + | hostdata->dev_param[i].synchronous_period; + + isp1020_mbox_command(host, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + restore_flags(flags); + printk("qlogicisp : set target parameter failure\n"); + return 1; + } + + for (k = 0; k < MAX_LUNS; k++) { + + param[0] = MBOX_SET_DEV_QUEUE_PARAMS; + param[1] = (i << 8) | k; + param[2] = hostdata->host_param.max_queue_depth; + param[3] = hostdata->dev_param[i].execution_throttle; + + isp1020_mbox_command(host, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + restore_flags(flags); + printk("qlogicisp : set device queue " + "parameter failure\n"); + return 1; + } + } + } + + queue_addr = (u_int) virt_to_bus(&hostdata->res[0][0]); + + param[0] = MBOX_INIT_RES_QUEUE; + param[1] = RES_QUEUE_LEN + 1; + param[2] = (u_short) (queue_addr >> 16); + param[3] = (u_short) (queue_addr & 0xffff); + param[4] = 0; + param[5] = 0; + + isp1020_mbox_command(host, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + restore_flags(flags); + printk("qlogicisp : set response queue failure\n"); + return 1; + } + + queue_addr = (u_int) virt_to_bus(&hostdata->req[0][0]); + + param[0] = MBOX_INIT_REQ_QUEUE; + param[1] = QLOGICISP_REQ_QUEUE_LEN + 1; + param[2] = (u_short) (queue_addr >> 16); + param[3] = (u_short) (queue_addr & 0xffff); + param[4] = 0; + + isp1020_mbox_command(host, param); + + if (param[0] != MBOX_COMMAND_COMPLETE) { + restore_flags(flags); + printk("qlogicisp : set request queue failure\n"); + return 1; + } -#if 0 restore_flags(flags); -#endif - } - isp1020_enable_irqs(hostdata); + LEAVE("isp1020_load_parameters"); - LEAVE_INTR("isp1020_intr_handler"); + return 0; } -#define NVRAM_DELAY() udelay(2) /* 2 microsecond delay */ - - -u_short isp1020_read_nvram_word(struct isp1020_hostdata *hostdata, u_short byte) -{ - int i; - u_short value, output, input; - - byte &= 0x3f; byte |= 0x0180; - - for (i = 8; i >= 0; i--) { - output = ((byte >> i) & 0x1) ? 0x4 : 0x0; - outw(output | 0x2, hostdata->io_base + PCI_NVRAM); NVRAM_DELAY(); - outw(output | 0x3, hostdata->io_base + PCI_NVRAM); NVRAM_DELAY(); - outw(output | 0x2, hostdata->io_base + PCI_NVRAM); NVRAM_DELAY(); - } - - for (i = 0xf, value = 0; i >= 0; i--) { - value <<= 1; - outw(0x3, hostdata->io_base + PCI_NVRAM); NVRAM_DELAY(); - input = inw(hostdata->io_base + PCI_NVRAM); NVRAM_DELAY(); - outw(0x2, hostdata->io_base + PCI_NVRAM); NVRAM_DELAY(); - if (input & 0x8) value |= 1; - } - - outw(0x0, hostdata->io_base + PCI_NVRAM); NVRAM_DELAY(); - - return(value); -} - -#define ISP1020_NVRAM_LEN 0x40 -#define ISP1020_NVRAM_SIG1 0x5349 -#define ISP1020_NVRAM_SIG2 0x2050 - -int isp1020_verify_nvram(struct isp1020_hostdata *hostdata) +/* + * currently, this is only called during initialization or abort/reset, + * at which times interrupts are disabled, so polling is OK, I guess... + */ +static int isp1020_mbox_command(struct Scsi_Host *host, u_short param[]) { - int i; - u_short value; - u_char checksum = 0; - - for (i = 0; i < ISP1020_NVRAM_LEN; i++) { - value = isp1020_read_nvram_word(hostdata, i); - - switch (i) { - case 0: - if (value != ISP1020_NVRAM_SIG1) return 0; - break; - case 1: - if (value != ISP1020_NVRAM_SIG2) return 0; - break; - case 2: - if ((value & 0xff) != 0x02) return 0; - break; - } - checksum += value & 0xff; - checksum += value >> 8; - } - - return (checksum == 0); -} + int loop_count; + if (mbox_param[param[0]] == 0) + return 1; -void isp1020_enable_irqs(struct isp1020_hostdata *hostdata) -{ - outw(ISP_EN_INT|ISP_EN_RISC, hostdata->io_base + PCI_INTF_CTL); -} + loop_count = DEFAULT_LOOP_COUNT; + while (--loop_count && inw(host->io_port + HOST_HCCR) & 0x0080) + barrier(); + if (!loop_count) + printk("qlogicisp: mbox_command loop timeout #1\n"); + + switch(mbox_param[param[0]] >> 4) { + case 6: outw(param[5], host->io_port + MBOX5); + case 5: outw(param[4], host->io_port + MBOX4); + case 4: outw(param[3], host->io_port + MBOX3); + case 3: outw(param[2], host->io_port + MBOX2); + case 2: outw(param[1], host->io_port + MBOX1); + case 1: outw(param[0], host->io_port + MBOX0); + } + + outw(0x0, host->io_port + PCI_SEMAPHORE); + outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); + outw(HCCR_SET_HOST_INTR, host->io_port + HOST_HCCR); + + loop_count = DEFAULT_LOOP_COUNT; + while (--loop_count && !(inw(host->io_port + PCI_INTF_STS) & 0x04)) + barrier(); + if (!loop_count) + printk("qlogicisp: mbox_command loop timeout #2\n"); + + loop_count = DEFAULT_LOOP_COUNT; + while (--loop_count && inw(host->io_port + MBOX0) == 0x04) + barrier(); + if (!loop_count) + printk("qlogicisp: mbox_command loop timeout #3\n"); + + switch(mbox_param[param[0]] & 0xf) { + case 6: param[5] = inw(host->io_port + MBOX5); + case 5: param[4] = inw(host->io_port + MBOX4); + case 4: param[3] = inw(host->io_port + MBOX3); + case 3: param[2] = inw(host->io_port + MBOX2); + case 2: param[1] = inw(host->io_port + MBOX1); + case 1: param[0] = inw(host->io_port + MBOX0); + } + outw(0x0, host->io_port + PCI_SEMAPHORE); + outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR); -void isp1020_disable_irqs(struct isp1020_hostdata *hostdata) -{ - outw(0x0, hostdata->io_base + PCI_INTF_CTL); + return 0; } @@ -1554,20 +1715,20 @@ void isp1020_print_status_entry(struct Status_Entry *status) { - int i; + int i; - printk("qlogicisp : entry count = 0x%02x, type = 0x%02x, flags = 0x%02x\n", - status->hdr.entry_cnt, status->hdr.entry_type, status->hdr.flags); - printk("qlogicisp : scsi status = 0x%04x, completion status = 0x%04x\n", - status->scsi_status, status->completion_status); - printk("qlogicisp : state flags = 0x%04x, status flags = 0x%04x\n", - status->state_flags, status->status_flags); - printk("qlogicisp : time = 0x%04x, request sense length = 0x%04x\n", - status->time, status->req_sense_len); - printk("qlogicisp : residual transfer length = 0x%08x\n", status->residual); + printk("qlogicisp : entry count = 0x%02x, type = 0x%02x, flags = 0x%02x\n", + status->hdr.entry_cnt, status->hdr.entry_type, status->hdr.flags); + printk("qlogicisp : scsi status = 0x%04x, completion status = 0x%04x\n", + status->scsi_status, status->completion_status); + printk("qlogicisp : state flags = 0x%04x, status flags = 0x%04x\n", + status->state_flags, status->status_flags); + printk("qlogicisp : time = 0x%04x, request sense length = 0x%04x\n", + status->time, status->req_sense_len); + printk("qlogicisp : residual transfer length = 0x%08x\n", status->residual); - for (i = 0; i < status->req_sense_len; i++) - printk("qlogicisp : sense data = 0x%02x\n", status->req_sense_data[i]); + for (i = 0; i < status->req_sense_len; i++) + printk("qlogicisp : sense data = 0x%02x\n", status->req_sense_data[i]); } #endif /* DEBUG_ISP1020_INTR */ @@ -1577,105 +1738,18 @@ void isp1020_print_scsi_cmd(Scsi_Cmnd *cmd) { - int i; + int i; - printk("qlogicisp : target = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n", - cmd->target, cmd->lun, cmd->cmd_len); - printk("qlogicisp : command = "); - for (i = 0; i < cmd->cmd_len; i++) - printk("0x%02x ", cmd->cmnd[i]); - printk("\n"); + printk("qlogicisp : target = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n", + cmd->target, cmd->lun, cmd->cmd_len); + printk("qlogicisp : command = "); + for (i = 0; i < cmd->cmd_len; i++) + printk("0x%02x ", cmd->cmnd[i]); + printk("\n"); } #endif /* DEBUG_ISP1020 */ - -int isp1020_return_status(struct Status_Entry *sts) -{ - int host_status = DID_ERROR; -#if DEBUG_ISP1020_INTR - static char *reason[] = { - "DID_OK", - "DID_NO_CONNECT", - "DID_BUS_BUSY", - "DID_TIME_OUT", - "DID_BAD_TARGET", - "DID_ABORT", - "DID_PARITY", - "DID_ERROR", - "DID_RESET", - "DID_BAD_INTR" - }; -#endif /* DEBUG_ISP1020_INTR */ - - ENTER("isp1020_return_status"); - - DEBUG(printk("qlogicisp : completion status = 0x%04x\n", - sts->completion_status);) - - switch(sts->completion_status) { - case CS_COMPLETE: - host_status = DID_OK; - break; - case CS_INCOMPLETE: - if (!(sts->state_flags & SF_GOT_BUS)) - host_status = DID_NO_CONNECT; - else if (!(sts->state_flags & SF_GOT_TARGET)) - host_status = DID_BAD_TARGET; - else if (!(sts->state_flags & SF_SENT_CDB)) - host_status = DID_ERROR; - else if (!(sts->state_flags & SF_TRANSFERRED_DATA)) - host_status = DID_ERROR; - else if (!(sts->state_flags & SF_GOT_STATUS)) - host_status = DID_ERROR; - else if (!(sts->state_flags & SF_GOT_SENSE)) - host_status = DID_ERROR; - break; - case CS_DMA_ERROR: - case CS_TRANSPORT_ERROR: - host_status = DID_ERROR; - break; - case CS_RESET_OCCURRED: - host_status = DID_RESET; - break; - case CS_ABORTED: - host_status = DID_ABORT; - break; - case CS_TIMEOUT: - host_status = DID_TIME_OUT; - break; - case CS_DATA_OVERRUN: - case CS_COMMAND_OVERRUN: - case CS_STATUS_OVERRUN: - case CS_BAD_MESSAGE: - case CS_NO_MESSAGE_OUT: - case CS_EXT_ID_FAILED: - case CS_IDE_MSG_FAILED: - case CS_ABORT_MSG_FAILED: - case CS_NOP_MSG_FAILED: - case CS_PARITY_ERROR_MSG_FAILED: - case CS_DEVICE_RESET_MSG_FAILED: - case CS_ID_MSG_FAILED: - case CS_UNEXP_BUS_FREE: - host_status = DID_ERROR; - break; - case CS_DATA_UNDERRUN: - host_status = DID_OK; - break; - default: - printk("qlogicisp : unknown completion status 0x%04x\n", - sts->completion_status); - host_status = DID_ERROR; - break; - } - - DEBUG_INTR(printk("qlogicisp : host status (%s) scsi status %x\n", - reason[host_status], sts->scsi_status);) - - LEAVE("isp1020_return_status"); - - return (sts->scsi_status & STATUS_MASK) | (host_status << 16); -} #ifdef MODULE Scsi_Host_Template driver_template = QLOGICISP; diff -ur --new-file old/linux/drivers/scsi/qlogicisp.h new/linux/drivers/scsi/qlogicisp.h --- old/linux/drivers/scsi/qlogicisp.h Tue Jun 4 05:06:38 1996 +++ new/linux/drivers/scsi/qlogicisp.h Mon Jul 1 19:06:05 1996 @@ -43,6 +43,21 @@ #ifndef _QLOGICISP_H #define _QLOGICISP_H +/* + * With the qlogic interface, every queue slot can hold a SCSI + * command with up to 4 scatter/gather entries. If we need more + * than 4 entries, continuation entries can be used that hold + * another 7 entries each. Unlike for other drivers, this means + * that the maximum number of scatter/gather entries we can + * support at any given time is a function of the number of queue + * slots available. That is, host->can_queue and host->sg_tablesize + * are dynamic and _not_ independent. This all works fine because + * requests are queued serially and the scatter/gather limit is + * determined for each queue request anew. + */ +#define QLOGICISP_REQ_QUEUE_LEN 63 /* must be power of two - 1 */ +#define QLOGICISP_MAX_SG(ql) (4 + ((ql) > 0) ? 7*((ql) - 1) : 0) + int isp1020_detect(Scsi_Host_Template *); int isp1020_release(struct Scsi_Host *); const char * isp1020_info(struct Scsi_Host *); @@ -57,28 +72,28 @@ extern struct proc_dir_entry proc_scsi_isp1020; -#define QLOGICISP { \ - /* next */ NULL, \ - /* usage_count */ NULL, \ - /* proc dir */ NULL, \ - /* procfs info */ NULL, \ - /* name */ NULL, \ - /* detect */ isp1020_detect, \ - /* release */ isp1020_release, \ - /* info */ isp1020_info, \ - /* command */ NULL, \ - /* queuecommand */ isp1020_queuecommand, \ - /* abort */ isp1020_abort, \ - /* reset */ isp1020_reset, \ - /* slave_attach */ NULL, \ - /* bios_param */ isp1020_biosparam, \ - /* can_queue */ 8, \ - /* this_id */ -1, \ - /* sg_tablesize */ 4, \ - /* cmd_per_lun */ 1, \ - /* present */ 0, \ - /* unchecked_isa_dma */ 0, \ - /* use_clustering */ DISABLE_CLUSTERING \ +#define QLOGICISP { \ + /* next */ NULL, \ + /* usage_count */ NULL, \ + /* proc dir */ NULL, \ + /* procfs info */ NULL, \ + /* name */ NULL, \ + /* detect */ isp1020_detect, \ + /* release */ isp1020_release, \ + /* info */ isp1020_info, \ + /* command */ NULL, \ + /* queuecommand */ isp1020_queuecommand, \ + /* abort */ isp1020_abort, \ + /* reset */ isp1020_reset, \ + /* slave_attach */ NULL, \ + /* bios_param */ isp1020_biosparam, \ + /* can_queue */ QLOGICISP_REQ_QUEUE_LEN, \ + /* this_id */ -1, \ + /* sg_tablesize */ QLOGICISP_MAX_SG(QLOGICISP_REQ_QUEUE_LEN), \ + /* cmd_per_lun */ 1, \ + /* present */ 0, \ + /* unchecked_isa_dma */ 0, \ + /* use_clustering */ DISABLE_CLUSTERING \ } #endif /* _QLOGICISP_H */ diff -ur --new-file old/linux/drivers/scsi/scsi.c new/linux/drivers/scsi/scsi.c --- old/linux/drivers/scsi/scsi.c Fri Jun 7 10:46:54 1996 +++ new/linux/drivers/scsi/scsi.c Thu Aug 1 14:43:04 1996 @@ -92,7 +92,7 @@ static void print_inquiry(unsigned char *data); static void scsi_times_out (Scsi_Cmnd * SCpnt); static int scan_scsis_single (int channel,int dev,int lun,int * max_scsi_dev , - Scsi_Device ** SDpnt, Scsi_Cmnd * SCpnt, + int * sparse_lun, Scsi_Device ** SDpnt, Scsi_Cmnd * SCpnt, struct Scsi_Host *shpnt, char * scsi_result); void scsi_build_commandblocks(Scsi_Device * SDpnt); @@ -167,19 +167,6 @@ #endif /* - * As the scsi do command functions are intelligent, and may need to - * redo a command, we need to keep track of the last command - * executed on each one. - */ - -#define WAS_RESET 0x01 -#define WAS_TIMEDOUT 0x02 -#define WAS_SENSE 0x04 -#define IS_RESETTING 0x08 -#define IS_ABORTING 0x10 -#define ASKED_FOR_SENSE 0x20 - -/* * This is the number of clock ticks we should wait before we time out * and abort the command. This is for where the scsi.c module generates * the command, not where it originates from a higher level, in which @@ -226,6 +213,7 @@ #define BLIST_KEY 0x08 #define BLIST_SINGLELUN 0x10 #define BLIST_NOTQ 0x20 +#define BLIST_SPARSELUN 0x40 struct dev_info{ const char * vendor; @@ -292,7 +280,8 @@ {"NRC","MBR-7","*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"PIONEER","CD-ROM DRM-602X","*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"PIONEER","CD-ROM DRM-604X","*", BLIST_FORCELUN | BLIST_SINGLELUN}, -{"EMULEX","MD21/S2 ESDI","*",BLIST_SINGLELUN}, +{"EMULEX","MD21/S2 ESDI","*", BLIST_SINGLELUN}, +{"CANON","IPUBJD","*", BLIST_SPARSELUN}, /* * Must be at end of list... */ @@ -415,7 +404,7 @@ unsigned char scsi_result0[256]; unsigned char *scsi_result; Scsi_Device *SDpnt; - int max_dev_lun; + int max_dev_lun, sparse_lun; Scsi_Cmnd *SCpnt; SCpnt = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd), GFP_ATOMIC | GFP_DMA); @@ -449,8 +438,8 @@ if(dev >= shpnt->max_id) goto leave; lun = hlun; if(lun >= shpnt->max_lun) goto leave; - scan_scsis_single (channel, dev, lun, &max_dev_lun, - &SDpnt, SCpnt, shpnt, scsi_result); + scan_scsis_single (channel, dev, lun, &max_dev_lun, &sparse_lun, + &SDpnt, SCpnt, shpnt, scsi_result); if(SDpnt!=oldSDpnt) { /* it could happen the blockdevice hasn't yet been inited */ @@ -483,9 +472,12 @@ */ max_dev_lun = (max_scsi_luns < shpnt->max_lun ? max_scsi_luns : shpnt->max_lun); + sparse_lun = 0; for (lun = 0; lun < max_dev_lun; ++lun) { if (!scan_scsis_single (channel, dev, lun, &max_dev_lun, - &SDpnt, SCpnt, shpnt, scsi_result)) + &sparse_lun, &SDpnt, SCpnt, shpnt, + scsi_result) + && !sparse_lun) break; /* break means don't probe further for luns!=0 */ } /* for lun ends */ } /* if this_id != id ends */ @@ -528,8 +520,8 @@ * Global variables used : scsi_devices(linked list) */ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun, - Scsi_Device **SDpnt2, Scsi_Cmnd * SCpnt, struct Scsi_Host * shpnt, - char *scsi_result) + int *sparse_lun, Scsi_Device **SDpnt2, Scsi_Cmnd * SCpnt, + struct Scsi_Host * shpnt, char *scsi_result) { unsigned char scsi_cmd[12]; struct Scsi_Device_Template *sdtpnt; @@ -796,6 +788,16 @@ SDpnt->single_lun = 1; /* + * If this device is known to support sparse multiple units, override the + * other settings, and scan all of them. + */ + if (bflags & BLIST_SPARSELUN) { + *max_dev_lun = 8; + *sparse_lun = 1; + return 1; + } + + /* * If this device is known to support multiple units, override the other * settings, and scan all of them. */ @@ -863,8 +865,7 @@ SCpnt->internal_timeout |= IN_RESET2; scsi_reset (SCpnt, SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_BUS_RESET); - return; - + return; case (IN_ABORT | IN_RESET | IN_RESET2): /* Obviously the bus reset didn't work. * Let's try even harder and call for an HBA reset. @@ -1184,27 +1185,47 @@ inline void internal_cmnd (Scsi_Cmnd * SCpnt) { - int temp; + unsigned long flags, timeout; struct Scsi_Host * host; - unsigned int flags; #ifdef DEBUG_DELAY - int clock; + unsigned long clock; +#endif + +#if DEBUG + unsigned long *ret = 0; +#ifdef __mips__ + __asm__ __volatile__ ("move\t%0,$31":"=r"(ret)); +#else + ret = __builtin_return_address(0); +#endif #endif host = SCpnt->host; - /* - * We will wait MIN_RESET_DELAY clock ticks after the last reset so - * we can avoid the drive not being ready. - */ save_flags(flags); cli(); /* Assign a unique nonzero serial_number. */ if (++serial_number == 0) serial_number = 1; SCpnt->serial_number = serial_number; - sti(); - temp = host->last_reset + MIN_RESET_DELAY; - while (jiffies < temp); + + /* + * We will wait MIN_RESET_DELAY clock ticks after the last reset so + * we can avoid the drive not being ready. + */ + timeout = host->last_reset + MIN_RESET_DELAY; + if (jiffies < timeout) { + /* + * NOTE: This may be executed from within an interrupt + * handler! This is bad, but for now, it'll do. The irq + * level of the interrupt handler has been masked out by the + * platform dependent interrupt handling code already, so the + * sti() here will not cause another call to the SCSI host's + * interrupt handler (assuming there is one irq-level per + * host). + */ + sti(); + while (jiffies < timeout) barrier(); + } restore_flags(flags); update_timeout(SCpnt, SCpnt->timeout_per_command); @@ -1245,15 +1266,16 @@ } else { - + int temp; + #ifdef DEBUG printk("command() : routine at %p\n", host->hostt->command); #endif - temp=host->hostt->command (SCpnt); + temp = host->hostt->command (SCpnt); SCpnt->result = temp; #ifdef DEBUG_DELAY clock = jiffies + 4 * HZ; - while (jiffies < clock); + while (jiffies < clock) barrier(); printk("done(host = %d, result = %04x) : routine at %p\n", host->host_no, temp, host->hostt->command); #endif @@ -1366,9 +1388,9 @@ SCpnt->serial_number = 0; SCpnt->bufflen = bufflen; SCpnt->buffer = buffer; - SCpnt->flags=0; - SCpnt->retries=0; - SCpnt->allowed=retries; + SCpnt->flags = 0; + SCpnt->retries = 0; + SCpnt->allowed = retries; SCpnt->done = done; SCpnt->timeout_per_command = timeout; @@ -1386,7 +1408,7 @@ /* Start the timer ticking. */ - SCpnt->internal_timeout = 0; + SCpnt->internal_timeout = NORMAL_TIMEOUT; SCpnt->abort_reason = 0; internal_cmnd (SCpnt); @@ -1553,7 +1575,8 @@ if (SCpnt->flags & WAS_SENSE) { #ifdef DEBUG - printk ("In scsi_done, GOOD status, COMMAND COMPLETE, parsing sense information.\n"); + printk ("In scsi_done, GOOD status, COMMAND COMPLETE, " + "parsing sense information.\n"); #endif SCpnt->flags &= ~WAS_SENSE; #if 0 /* This cannot possibly be correct. */ @@ -1601,7 +1624,8 @@ else { #ifdef DEBUG - printk("COMMAND COMPLETE message returned, status = FINISHED. \n"); + printk("COMMAND COMPLETE message returned, " + "status = FINISHED. \n"); #endif exit = DRIVER_OK; status = FINISHED; @@ -1609,6 +1633,7 @@ break; case CHECK_CONDITION: + case COMMAND_TERMINATED: switch (check_sense(SCpnt)) { case 0: @@ -1640,6 +1665,7 @@ break; case BUSY: + case QUEUE_FULL: update_timeout(SCpnt, oldto); status = REDO; break; @@ -2055,10 +2081,11 @@ * Protect against races here. If the command is done, or we are * on a different command forget it. */ - if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) { + if (reset_flags & SCSI_RESET_ASYNCHRONOUS) + if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) { restore_flags(flags); return 0; - } + } if (SCpnt->internal_timeout & IN_RESET) { @@ -2372,8 +2399,15 @@ { unsigned int page, sector, nbits, mask; unsigned long flags; - + #ifdef DEBUG + unsigned long ret = 0; + +#ifdef __mips__ + __asm__ __volatile__ ("move\t%0,$31":"=r"(ret)); +#else + ret = __builtin_return_address(0); +#endif printk("scsi_free %p %d\n",obj, len); #endif @@ -2392,9 +2426,14 @@ save_flags(flags); cli(); - if((dma_malloc_freelist[page] & (mask << sector)) != (mask<next) { host = SDpnt->host; - if(SDpnt->type != TYPE_TAPE) + /* + * sd and sr drivers allocate scatterlists. + * sr drivers may allocate for each command 1x2048 or 2x1024 extra + * buffers for 2k sector size and 1k fs. + * sg driver allocates buffers < 4k. + * st driver does not need buffers from the dma pool. + * estimate 4k buffer/command for devices of unknown type (should panic). + */ + if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM || + SDpnt->type == TYPE_DISK || SDpnt->type == TYPE_MOD) { new_dma_sectors += ((host->sg_tablesize * sizeof(struct scatterlist) + 511) >> 9) * SDpnt->queue_depth; - + if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM) + new_dma_sectors += (2048 >> 9) * SDpnt->queue_depth; + } + else if (SDpnt->type == TYPE_SCANNER || SDpnt->type == TYPE_PROCESSOR) { + new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth; + } + else { + if (SDpnt->type != TYPE_TAPE) { + printk("resize_dma_pool: unknown device type %d\n", SDpnt->type); + new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth; + } + } + if(host->unchecked_isa_dma && scsi_need_isa_bounce_buffers && SDpnt->type != TYPE_TAPE) { @@ -2858,7 +2918,11 @@ new_need_isa_buffer++; } } - + +#ifdef DEBUG_INIT + printk("resize_dma_pool: needed dma sectors = %d\n", new_dma_sectors); +#endif + /* limit DMA memory to 32MB: */ new_dma_sectors = (new_dma_sectors + 15) & 0xfff0; @@ -2915,6 +2979,12 @@ dma_sectors = new_dma_sectors; need_isa_buffer = new_need_isa_buffer; restore_flags(flags); + +#ifdef DEBUG_INIT + printk("resize_dma_pool: dma free sectors = %d\n", dma_free_sectors); + printk("resize_dma_pool: dma sectors = %d\n", dma_sectors); + printk("resize_dma_pool: need isa buffers = %d\n", need_isa_buffer); +#endif } #ifdef CONFIG_MODULES /* a big #ifdef block... */ diff -ur --new-file old/linux/drivers/scsi/scsi.h new/linux/drivers/scsi/scsi.h --- old/linux/drivers/scsi/scsi.h Thu Jun 6 12:42:15 1996 +++ new/linux/drivers/scsi/scsi.h Mon Jul 8 09:41:07 1996 @@ -202,7 +202,7 @@ * Use these to separate status msg and our bytes */ -#define status_byte(result) (((result) >> 1) & 0xf) +#define status_byte(result) (((result) >> 1) & 0x1f) #define msg_byte(result) (((result) >> 8) & 0xff) #define host_byte(result) (((result) >> 16) & 0xff) #define driver_byte(result) (((result) >> 24) & 0xff) diff -ur --new-file old/linux/drivers/scsi/scsi_ioctl.c new/linux/drivers/scsi/scsi_ioctl.c --- old/linux/drivers/scsi/scsi_ioctl.c Sat Jun 8 10:41:46 1996 +++ new/linux/drivers/scsi/scsi_ioctl.c Tue Aug 13 08:27:47 1996 @@ -165,7 +165,7 @@ static int ioctl_command(Scsi_Device *dev, void *buffer) { char * buf; - char cmd[12]; + unsigned char cmd[12]; char * cmd_in; Scsi_Cmnd * SCpnt; unsigned char opcode; @@ -187,10 +187,10 @@ * The structure that we are passed should look like: * * struct sdata{ - * int inlen; - * int outlen; - * char cmd[]; # However many bytes are used for cmd. - * char data[]; + * unsigned int inlen; + * unsigned int outlen; + * unsigned char cmd[]; # However many bytes are used for cmd. + * unsigned char data[]; */ inlen = get_user((unsigned int *) buffer); outlen = get_user( ((unsigned int *) buffer) + 1); diff -ur --new-file old/linux/drivers/scsi/scsicam.c new/linux/drivers/scsi/scsicam.c --- old/linux/drivers/scsi/scsicam.c Thu Nov 30 13:04:51 1995 +++ new/linux/drivers/scsi/scsicam.c Sun Aug 4 12:39:07 1996 @@ -22,6 +22,7 @@ #include #include #include +#include #include "scsi.h" #include "hosts.h" #include "sd.h" @@ -121,7 +122,8 @@ end_head * end_sector + end_sector; /* This is the actual _sector_ number at the end */ - logical_end = largest->start_sect + largest->nr_sects; + logical_end = get_unaligned(&largest->start_sect) + + get_unaligned(&largest->nr_sects); /* This is for >1023 cylinders */ ext_cyl= (logical_end-(end_head * end_sector + end_sector)) diff -ur --new-file old/linux/drivers/scsi/sd.c new/linux/drivers/scsi/sd.c --- old/linux/drivers/scsi/sd.c Tue Jun 4 11:56:48 1996 +++ new/linux/drivers/scsi/sd.c Fri Aug 9 10:20:56 1996 @@ -490,6 +490,9 @@ if( SDev->removable && !intr_count ) { scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, 0); + /* scsi_ioctl may allow CURRENT to change, so start over. */ + SDev->was_reset = 0; + continue; } SDev->was_reset = 0; } @@ -729,9 +732,9 @@ ((unsigned int) SCpnt->request.bh->b_data-1) == ISA_DMA_THRESHOLD) count--; #endif SCpnt->use_sg = count; /* Number of chains */ - count = 512;/* scsi_malloc can only allocate in chunks of 512 bytes */ - while( count < (SCpnt->use_sg * sizeof(struct scatterlist))) - count = count << 1; + /* scsi_malloc can only allocate in chunks of 512 bytes */ + count = (SCpnt->use_sg * sizeof(struct scatterlist) + 511) & ~511; + SCpnt->sglist_len = count; max_sg = count / sizeof(struct scatterlist); if(SCpnt->host->sg_tablesize < max_sg) @@ -1054,7 +1057,7 @@ * Issue command to spin up drive for these cases. */ if(the_result && !rscsi_disks[i].device->removable && SCpnt->sense_buffer[2] == NOT_READY) { - int time1; + unsigned long time1; if(!spintime){ printk( "sd%c: Spinning up disk...", 'a' + i ); cmd[0] = START_STOP; @@ -1081,8 +1084,8 @@ spintime = jiffies; } - time1 = jiffies; - while(jiffies < time1 + HZ); /* Wait 1 second for next try */ + time1 = jiffies + HZ; + while(jiffies < time1); /* Wait 1 second for next try */ printk( "." ); } } while(the_result && spintime && spintime+100*HZ > jiffies); @@ -1388,7 +1391,8 @@ static int sd_detect(Scsi_Device * SDp){ if(SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0; - printk("Detected scsi disk sd%c at scsi%d, channel %d, id %d, lun %d\n", + printk("Detected scsi %sdisk sd%c at scsi%d, channel %d, id %d, lun %d\n", + SDp->removable ? "removable " : "", 'a'+ (sd_template.dev_noticed++), SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); diff -ur --new-file old/linux/drivers/scsi/sg.c new/linux/drivers/scsi/sg.c --- old/linux/drivers/scsi/sg.c Thu May 2 06:48:54 1996 +++ new/linux/drivers/scsi/sg.c Thu Aug 1 14:43:05 1996 @@ -230,7 +230,7 @@ * Now copy the result back to the user buffer. */ device->header.pack_len=device->header.reply_len; - device->header.result=0; + if (count>=sizeof(struct sg_header)) { memcpy_tofs(buf,&device->header,sizeof(struct sg_header)); @@ -242,7 +242,7 @@ } } else - count=0; + count= device->header.result==0 ? 0 : -EIO; /* * Clean up, and release the device so that we can send another @@ -276,12 +276,7 @@ * wrong. */ memcpy(device->header.sense_buffer, SCpnt->sense_buffer, sizeof(SCpnt->sense_buffer)); - if (SCpnt->sense_buffer[0]) - { - device->header.result=EIO; - } - else - device->header.result=SCpnt->result; + device->header.result = (SCpnt->sense_buffer[0] == 0 ? 0 : EIO); /* * Now wake up the process that is waiting for the @@ -593,6 +588,11 @@ gpnt->device = NULL; SDp->attached--; sg_template.nr_dev--; + /* + * avoid associated device /dev/sg? bying incremented + * each time module is inserted/removed , + */ + sg_template.dev_noticed--; return; } return; diff -ur --new-file old/linux/drivers/scsi/sr.c new/linux/drivers/scsi/sr.c --- old/linux/drivers/scsi/sr.c Thu Jun 6 17:29:56 1996 +++ new/linux/drivers/scsi/sr.c Tue Aug 13 08:27:48 1996 @@ -427,8 +427,8 @@ printk(KERN_DEBUG "sr_photocd: use NEC code\n"); #endif memset(buf,0,40); - *((unsigned long*)buf) = 0x0; /* we send nothing... */ - *((unsigned long*)buf+1) = 0x16; /* and receive 0x16 bytes */ + *((unsigned int*)buf) = 0x0; /* we send nothing... */ + *((unsigned int*)buf+1) = 0x16; /* and receive 0x16 bytes */ cmd[0] = 0xde; cmd[1] = 0x03; cmd[2] = 0xb0; @@ -464,10 +464,10 @@ /* we request some disc information (is it a XA-CD ?, * where starts the last session ?) */ memset(buf,0,40); - *((unsigned long*)buf) = 0; - *((unsigned long*)buf+1) = 4; /* we receive 4 bytes from the drive */ - cmd[0] = 0xc7; - cmd[1] = 3; + *((unsigned int*)buf) = (unsigned int) 0; + *((unsigned int*)buf+1) = (unsigned int) 4; /* receive 4 bytes */ + cmd[0] = (unsigned char) 0x00c7; + cmd[1] = (unsigned char) 3; rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device, SCSI_IOCTL_SEND_COMMAND, buf); if (rc != 0) { @@ -499,11 +499,11 @@ /* now we do a get_density... */ memset(buf,0,40); - *((unsigned long*)buf) = 0; - *((unsigned long*)buf+1) = 12; - cmd[0] = MODE_SENSE; - cmd[2] = 1; - cmd[4] = 12; + *((unsigned int*)buf) = (unsigned int) 0; + *((unsigned int*)buf+1) = (unsigned int) 12; + cmd[0] = (unsigned char) MODE_SENSE; + cmd[2] = (unsigned char) 1; + cmd[4] = (unsigned char) 12; rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device, SCSI_IOCTL_SEND_COMMAND, buf); if (rc != 0) { @@ -520,15 +520,17 @@ printk(KERN_DEBUG "sr_photocd: doing set_density\n"); #endif memset(buf,0,40); - *((unsigned long*)buf) = 12; /* sending 12 bytes... */ - *((unsigned long*)buf+1) = 0; - cmd[0] = MODE_SELECT; - cmd[1] = (1 << 4); - cmd[4] = 12; - send = &cmd[6]; /* this is a 6-Byte command */ - send[ 3] = 0x08; /* the data for the command */ - send[ 4] = (is_xa) ? 0x81 : 0; /* density 0x81 for XA, 0 else */ - send[10] = 0x08; + *((unsigned int*)buf) = (unsigned int) 12; /* send 12 bytes */ + *((unsigned int*)buf+1) = (unsigned int) 0; + cmd[0] = (unsigned char) MODE_SELECT; + cmd[1] = (unsigned char) (1 << 4); + cmd[4] = (unsigned char) 12; + send = &cmd[6]; /* this is a 6-Byte command */ + send[ 3] = (unsigned char) 0x08; /* data for cmd */ + /* density 0x81 for XA, 0 else */ + send[ 4] = (is_xa) ? + (unsigned char) 0x81 : (unsigned char) 0; + send[10] = (unsigned char) 0x08; rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device, SCSI_IOCTL_SEND_COMMAND, buf); if (rc != 0) { @@ -547,8 +549,8 @@ #endif get_sectorsize(MINOR(inode->i_rdev)); /* spinup (avoid timeout) */ memset(buf,0,40); - *((unsigned long*)buf) = 0x0; /* we send nothing... */ - *((unsigned long*)buf+1) = 0x0c; /* and receive 0x0c bytes */ + *((unsigned int*)buf) = 0x0; /* we send nothing... */ + *((unsigned int*)buf+1) = 0x0c; /* and receive 0x0c bytes */ cmd[0] = READ_TOC; cmd[8] = 0x0c; cmd[9] = 0x40; @@ -822,9 +824,9 @@ }; }; SCpnt->use_sg = count; /* Number of chains */ - count = 512;/* scsi_malloc can only allocate in chunks of 512 bytes*/ - while( count < (SCpnt->use_sg * sizeof(struct scatterlist))) - count = count << 1; + /* scsi_malloc can only allocate in chunks of 512 bytes */ + count = (SCpnt->use_sg * sizeof(struct scatterlist) + 511) & ~511; + SCpnt->sglist_len = count; sgpnt = (struct scatterlist * ) scsi_malloc(count); if (!sgpnt) { diff -ur --new-file old/linux/drivers/scsi/st.c new/linux/drivers/scsi/st.c --- old/linux/drivers/scsi/st.c Sat May 18 12:25:09 1996 +++ new/linux/drivers/scsi/st.c Fri Aug 16 07:02:48 1996 @@ -11,7 +11,7 @@ Copyright 1992 - 1996 Kai Makisara email Kai.Makisara@metla.fi - Last modified: Tue May 14 17:58:12 1996 by makisara@kai.makisara.fi + Last modified: Sun Jul 7 10:08:46 1996 by root@kai.makisara.fi Some small formal changes - aeb, 950809 */ @@ -41,6 +41,7 @@ #define MAJOR_NR SCSI_TAPE_MAJOR #include + #include "scsi.h" #include "hosts.h" #include @@ -143,6 +144,8 @@ } #endif scode = sense[2] & 0x0f; + +#if !DEBUG if (!(driver_byte(result) & DRIVER_SENSE) || ((sense[0] & 0x70) == 0x70 && scode != NO_SENSE && @@ -152,15 +155,14 @@ scode != VOLUME_OVERFLOW && SCpnt->data_cmnd[0] != MODE_SENSE && SCpnt->data_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */ -#if !DEBUG if (driver_byte(result) & DRIVER_SENSE) { printk(KERN_WARNING "st%d: Error with sense data: ", dev); print_sense("st", SCpnt); } else printk(KERN_WARNING "st%d: Error %x.\n", dev, result); -#endif } +#endif if ((sense[0] & 0x70) == 0x70 && scode == RECOVERED_ERROR @@ -172,7 +174,7 @@ scsi_tapes[dev].recover_count++; scsi_tapes[dev].mt_status->mt_erreg += (1 << MT_ST_SOFTERR_SHIFT); #if DEBUG - if (debugging) { /* This is compiled always on purpose */ + if (debugging) { if (SCpnt->data_cmnd[0] == READ_6) stp = "read"; else if (SCpnt->data_cmnd[0] == WRITE_6) @@ -380,16 +382,17 @@ return (-EBUSY); if ((STp->buffer)->last_result_fatal != 0) { - printk(KERN_ERR "st%d: Error on flush.\n", TAPE_NR(STp->devt)); if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 && (SCpnt->sense_buffer[2] & 0x40) && - (SCpnt->sense_buffer[2] & 0x0f) != VOLUME_OVERFLOW) { + (SCpnt->sense_buffer[2] & 0x0f) == NO_SENSE) { STp->dirty = 0; (STp->buffer)->buffer_bytes = 0; result = (-ENOSPC); } - else + else { + printk(KERN_ERR "st%d: Error on flush.\n", TAPE_NR(STp->devt)); result = (-EIO); + } STp->drv_block = (-1); } else { @@ -455,7 +458,8 @@ result = st_int_ioctl(inode, MTBSR, backspace); } else if ((STp->eof == ST_FM) && !STp->eof_hit) { - (STp->mt_status)->mt_fileno++; + if ((STp->mt_status)->mt_fileno >= 0) + (STp->mt_status)->mt_fileno++; STp->drv_block = 0; } @@ -832,7 +836,13 @@ SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */ - if ((STp->buffer)->last_result_fatal != 0) + if ((STp->buffer)->last_result_fatal != 0 && + ((SCpnt->sense_buffer[0] & 0x70) != 0x70 || + (SCpnt->sense_buffer[2] & 0x4f) != 0x40 || + ((SCpnt->sense_buffer[0] & 0x80) != 0 && + (SCpnt->sense_buffer[3] | SCpnt->sense_buffer[4] | + SCpnt->sense_buffer[5] | + SCpnt->sense_buffer[6]) == 0))) /* Filter out successful write at EOM */ printk(KERN_ERR "st%d: Error on write filemark.\n", dev); else { if ((STp->mt_status)->mt_fileno >= 0) @@ -1266,6 +1276,9 @@ #endif if ((SCpnt->sense_buffer[0] & 0x70) == 0x70) { /* extended sense */ + if ((SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK) + SCpnt->sense_buffer[2] &= 0xcf; /* No need for EOM in this case */ + if ((SCpnt->sense_buffer[2] & 0xe0) != 0) { /* EOF, EOM, or ILI */ if ((SCpnt->sense_buffer[0] & 0x80) != 0) @@ -1309,31 +1322,31 @@ SCpnt = NULL; } } - else if (SCpnt->sense_buffer[2] & 0x40) { - STp->eof = ST_EOM_OK; + else if (SCpnt->sense_buffer[2] & 0x80) { /* FM overrides EOM */ + STp->eof = ST_FM; if (STp->block_size == 0) - (STp->buffer)->buffer_bytes = bytes - transfer; + (STp->buffer)->buffer_bytes = 0; else (STp->buffer)->buffer_bytes = bytes - transfer * STp->block_size; #if DEBUG if (debugging) - printk(ST_DEB_MSG "st%d: EOM detected (%d bytes read).\n", dev, - (STp->buffer)->buffer_bytes); + printk(ST_DEB_MSG + "st%d: EOF detected (%d bytes read, transferred %d bytes).\n", + dev, (STp->buffer)->buffer_bytes, total); #endif } - else if (SCpnt->sense_buffer[2] & 0x80) { - STp->eof = ST_FM; + else if (SCpnt->sense_buffer[2] & 0x40) { + STp->eof = ST_EOM_OK; if (STp->block_size == 0) - (STp->buffer)->buffer_bytes = 0; + (STp->buffer)->buffer_bytes = bytes - transfer; else (STp->buffer)->buffer_bytes = bytes - transfer * STp->block_size; #if DEBUG if (debugging) - printk(ST_DEB_MSG - "st%d: EOF detected (%d bytes read, transferred %d bytes).\n", - dev, (STp->buffer)->buffer_bytes, total); + printk(ST_DEB_MSG "st%d: EOM detected (%d bytes read).\n", dev, + (STp->buffer)->buffer_bytes); #endif } } /* end of EOF, EOM, ILI test */ @@ -1402,6 +1415,7 @@ SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */ if (total == 0 && STp->eof == ST_FM) { STp->eof = ST_NOEOF; + STp->eof_hit = 0; STp->drv_block = 0; if (STps->moves_after_eof > 1) STps->moves_after_eof = 0; @@ -1409,7 +1423,7 @@ (STp->mt_status)->mt_fileno++; } if (total == 0 && STp->eof == ST_EOM_OK) - return (-EIO); /* ST_EOM_ERROR not used in read */ + return (-ENOSPC); /* ST_EOM_ERROR not used in read */ return total; } @@ -1677,7 +1691,7 @@ SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */ STp->compression_changed = TRUE; - return 0; /* Not implemented yet */ + return 0; } @@ -2026,7 +2040,9 @@ if (cmd_in == MTFSF) STps->moves_after_eof = 0; - else if (cmd_in != MTLOAD) + else if (cmd_in != MTLOAD && cmd_in != MTLOCK && cmd_in != MTUNLOCK && + cmd_in != MTSETBLK && cmd_in != MTSETDENSITY && + cmd_in != MTSETDRVBUFFER) STps->moves_after_eof = 1; if (!ioctl_result) { /* SCSI command successful */ STp->drv_block = blkno; @@ -2085,7 +2101,16 @@ (SCpnt->sense_buffer[4] << 16) + (SCpnt->sense_buffer[5] << 8) + SCpnt->sense_buffer[6] ); - if ( (cmd_in == MTFSF) || (cmd_in == MTFSFM) ) { + if (cmd_in == MTWEOF && + (SCpnt->sense_buffer[0] & 0x70) == 0x70 && + (SCpnt->sense_buffer[2] & 0x4f) == 0x40 && + ((SCpnt->sense_buffer[0] & 0x80) == 0 || undone == 0)) { + ioctl_result = 0; /* EOF written succesfully at EOM */ + if (fileno >= 0) + fileno++; + (STp->mt_status)->mt_fileno = fileno; + } + else if ( (cmd_in == MTFSF) || (cmd_in == MTFSFM) ) { if (fileno >= 0) (STp->mt_status)->mt_fileno = fileno - undone ; else @@ -2516,17 +2541,19 @@ if (!(STp->device)->was_reset) { if (STp->eof_hit) { - if (mtc.mt_op == MTFSF || mtc.mt_op == MTEOM) { + if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM|| mtc.mt_op == MTEOM) { mtc.mt_count -= 1; - (STp->mt_status)->mt_fileno += 1; + if ((STp->mt_status)->mt_fileno >= 0) + (STp->mt_status)->mt_fileno += 1; } - else if (mtc.mt_op == MTBSF) { + else if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) { mtc.mt_count += 1; - (STp->mt_status)->mt_fileno += 1; + if ((STp->mt_status)->mt_fileno >= 0) + (STp->mt_status)->mt_fileno += 1; } } - i = flush_buffer(inode, file, mtc.mt_op == MTSEEK || + i = flush_buffer(inode, file, /* mtc.mt_op == MTSEEK || */ mtc.mt_op == MTREW || mtc.mt_op == MTOFFL || mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM || mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD || @@ -2670,6 +2697,9 @@ (STp->mt_status)->mt_gstat |= GMT_DR_OPEN(0xffffffff); if (STps->at_sm) (STp->mt_status)->mt_gstat |= GMT_SM(0xffffffff); + if (STm->do_async_writes || (STm->do_buffer_writes && STp->block_size != 0) || + STp->drv_buffer != 0) + (STp->mt_status)->mt_gstat |= GMT_IM_REP_EN(0xffffffff); memcpy_tofs((char *)arg, (char *)(STp->mt_status), sizeof(struct mtget)); diff -ur --new-file old/linux/drivers/scsi/u14-34f.c new/linux/drivers/scsi/u14-34f.c --- old/linux/drivers/scsi/u14-34f.c Thu Apr 18 13:56:45 1996 +++ new/linux/drivers/scsi/u14-34f.c Wed Jul 10 07:05:27 1996 @@ -1,6 +1,10 @@ /* * u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters. * + * 09 Jul 1996 rev. 2.11 for linux 2.0.4 + * "Data over/under-run" no longer implies a redo on all targets. + * Number of internal retries is now limited. + * * 16 Apr 1996 rev. 2.10 for linux 1.3.90 * New argument "reset_flags" to the reset routine. * @@ -199,6 +203,7 @@ #define MAX_MAILBOXES 16 #define MAX_SGLIST 32 #define MAX_SAFE_SGLIST 16 +#define MAX_INTERNAL_RETRIES 64 #define MAX_CMD_PER_LUN 2 #define FALSE 0 @@ -280,6 +285,8 @@ int in_reset; /* True if board is doing a reset */ int target_time_out[MAX_TARGET]; /* N. of timeout errors on target */ int target_reset[MAX_TARGET]; /* If TRUE redo operation on target */ + unsigned int retries; /* Number of internal retries */ + unsigned long last_retried_pid; /* Pid of last retried command */ unsigned char subversion; /* Bus type, either ISA or ESA */ unsigned char heads; unsigned char sectors; @@ -763,6 +770,8 @@ return SCSI_RESET_ERROR; } + HD(j)->retries = 0; + for (k = 0; k < MAX_TARGET; k++) HD(j)->target_reset[k] = TRUE; for (k = 0; k < MAX_TARGET; k++) HD(j)->target_time_out[k] = 0; @@ -972,6 +981,8 @@ HD(j)->target_time_out[SCpnt->target] = 0; + if (HD(j)->last_retried_pid == SCpnt->pid) HD(j)->retries = 0; + break; case ASST: /* Selection Time Out */ @@ -983,20 +994,27 @@ } break; - case 0x92: /* Data over/under-run */ + + /* Perform a limited number of internal retries */ case 0x93: /* Unexpected bus free */ case 0x94: /* Target bus phase sequence failure */ case 0x96: /* Illegal SCSI command */ case 0xa3: /* SCSI bus reset error */ - if (SCpnt->device->type != TYPE_TAPE) - status = DID_BUS_BUSY << 16; - else - status = DID_ERROR << 16; - for (k = 0; k < MAX_TARGET; k++) HD(j)->target_reset[k] = TRUE; + case 0x92: /* Data over/under-run */ + + if (SCpnt->device->type != TYPE_TAPE + && HD(j)->retries < MAX_INTERNAL_RETRIES) { + status = DID_BUS_BUSY << 16; + HD(j)->retries++; + HD(j)->last_retried_pid = SCpnt->pid; + } + else + status = DID_ERROR << 16; + break; case 0x01: /* Invalid command */ case 0x02: /* Invalid parameters */ @@ -1023,7 +1041,7 @@ spp->adapter_status != ASST && HD(j)->iocount <= 1000) || do_trace) #endif - printk("%s: ihdlr, mbox %d, err 0x%x:%x,"\ + printk("%s: ihdlr, mbox %2d, err 0x%x:%x,"\ " target %d:%d, pid %ld, count %d.\n", BN(j), i, spp->adapter_status, spp->target_status, SCpnt->target, SCpnt->lun, SCpnt->pid, HD(j)->iocount); diff -ur --new-file old/linux/drivers/scsi/u14-34f.h new/linux/drivers/scsi/u14-34f.h --- old/linux/drivers/scsi/u14-34f.h Thu Apr 18 13:56:45 1996 +++ new/linux/drivers/scsi/u14-34f.h Wed Jul 10 07:05:27 1996 @@ -10,7 +10,7 @@ int u14_34f_reset(Scsi_Cmnd *, unsigned int); int u14_34f_biosparam(Disk *, kdev_t, int *); -#define U14_34F_VERSION "2.10.00" +#define U14_34F_VERSION "2.11.00" #define ULTRASTOR_14_34F { \ NULL, /* Ptr for modules */ \ diff -ur --new-file old/linux/drivers/sound/.blurb new/linux/drivers/sound/.blurb --- old/linux/drivers/sound/.blurb Sun Mar 24 21:49:48 1996 +++ new/linux/drivers/sound/.blurb Sun Jun 30 10:43:44 1996 @@ -1,8 +1,9 @@ ********************************************************* * Readme.cards (this directory) contains some card * * specific instructions. * -* See http://personal.eunet.fi/pp/voxware for most up * +* See http://www.4front-tech.com/usslite for most up * * to date info. * +* (European mirror http://personal.eunet.fi/pp/voxware) * * * * DON'T USE PROGRAMS FROM SND_UTIL PACKAGE EARLIER THAN * * snd-util-3.5 WITH THIS SOUND DRIVER VERSION. * diff -ur --new-file old/linux/drivers/sound/.object_files new/linux/drivers/sound/.object_files --- old/linux/drivers/sound/.object_files Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/sound/.object_files Sun Jun 30 10:50:18 1996 @@ -0,0 +1,35 @@ +audio.o +dmabuf.o +opl3.o +sequencer.o +midibuf.o +sb_card.o +pas2_card.o +adlib_card.o +pas2_pcm.o +pas2_mixer.o +pas2_midi.o +gus_card.o +gus_wave.o +mpu401.o +gus_midi.o +gus_vol.o +patmgr.o +sb_mixer.o +sb_common.o +midi_synth.o +uart6850.o +uart401.o +sound_timer.o +sb_midi.o +sb_audio.o +sys_timer.o +ics2101.o +ad1848.o +pss.o +sscape.o +trix.o +aedsp16.o +mad16.o +cs4232.o +maui.o diff -ur --new-file old/linux/drivers/sound/.objects new/linux/drivers/sound/.objects --- old/linux/drivers/sound/.objects Sun Mar 24 21:51:44 1996 +++ new/linux/drivers/sound/.objects Thu Aug 1 14:43:05 1996 @@ -29,7 +29,7 @@ endif ifdef CONFIG_MAD16 - OBJS := $(OBJS) mad16.o mad16_sb_midi.o + OBJS := $(OBJS) mad16.o endif ifdef CONFIG_MAUI @@ -64,12 +64,8 @@ OBJS := $(OBJS) pss.o endif -ifdef CONFIG_SB - OBJS := $(OBJS) sb16_midi.o sb_card.o sb_dsp.o sb_midi.o sb_mixer.o - OBJS := $(OBJS) sb_card.o - OBJS := $(OBJS) sb_dsp.o sb16_dsp.o - OBJS := $(OBJS) sb_midi.o - OBJS := $(OBJS) sb_mixer.o +ifdef CONFIG_SBDSP + OBJS := $(OBJS) sb_card.o sb_common.o sb_audio.o sb_mixer.o sb_midi.o endif ifdef CONFIG_SEQUENCER @@ -94,4 +90,8 @@ ifdef CONFIG_UART6850 OBJS := $(OBJS) uart6850.o +endif + +ifdef CONFIG_UART401 + OBJS := $(OBJS) uart401.o endif diff -ur --new-file old/linux/drivers/sound/.version new/linux/drivers/sound/.version --- old/linux/drivers/sound/.version Sat Mar 30 12:38:31 1996 +++ new/linux/drivers/sound/.version Sun Jun 30 10:43:44 1996 @@ -1,2 +1,2 @@ -3.5.2 -0x030500 +3.5.5-beta1 +0x030504 diff -ur --new-file old/linux/drivers/sound/CHANGELOG new/linux/drivers/sound/CHANGELOG --- old/linux/drivers/sound/CHANGELOG Mon May 6 11:26:11 1996 +++ new/linux/drivers/sound/CHANGELOG Sat Jul 6 10:31:43 1996 @@ -1,6 +1,59 @@ -Changelog for version 3.5.2 +Changelog for version 3.5.4 --------------------------- +Since 3.5.4-beta8 +- Fixed a bug in handling of non-fragment sized writes in 16 bit/stereo mode + with GUS. +- Limited minimum fragment size with some audio devices (GUS=512 and + SB=32). These devices require more time to "recover" from processing + of each fragment. + +Since 3.5.4-beta6/7 +- There seems to be problems in the OPTi 82C930 so cards based on this + chip don't necessarily work yet. There are problems in detecting the + MIDI interface. Also mixer volumes may be seriously wrong on some systems. + You can safely use this driver version with C930 if it looks to work. + However please don't complain if you have problems with it. C930 support + should be fixed in future releases. +- Got initialization of GUS PnP to work. With this version GUS PnP should + work in GUS compatible mode after initialization using isapnptools. +- Fixed a bug in handling of full duplex cards in write only mode. This has + been causing "audio device opening" errors with RealAudio player. + +Since 3.5.4.beta5 +- Changes to OPTi 82C930 driver. +- Major changes to the Soundscape driver. The driver requires now just one + DMA channel. The extra audio/dsp device (the "Not functional" one) used + for code download in the earlier versions has been eliminated. There is now + just one /dev/dsp# device which is used both for code download and audio. + +Since 3.5.4.beta4 +- Minor changes. + +Since 3.5.4-beta2 +- Fixed silent playback with ESS 688/1688. +- Got SB16 to work without the 16 bit DMA channel (only the 8 bit one + is required for 8 and 16 bit modes). +- Added the "lowlevel" subdirectory for additional low level drivers that + are not part of USS core. See lowlevel/README for more info. +- Included support for ACI mixer (by Markus Kuhn). ACI is a mixer used in + miroPCM soundcards. See lowlevel/aci.readme for more info. +- Support for Aztech Washington chipset (AZT2316 ASIC). + +Since 3.5.4-beta1 +- Reduced clicking with AD1848. +- Support for OPTi 82C930. Only half duplex at this time. 16 bit playback + is sometimes just white noise (occurs randomly). + +Since 3.5.2 +- Major changes to the SB/Jazz16/ESS driver (most parts rewritten). + The most noticeable new feature is support for multiple SB cards at the same + time. +- Renamed sb16_midi.c to uart401.c. Also modified it to work also with + other MPU401 UART compatible cards than SB16/ESS/Jazz. +- Some changes which reduce clicking in audio playback. +- Copying policy is now GPL. + Since 3.5.1 - TB Maui initialization support Since 3.5 @@ -47,14 +100,14 @@ to James Hightower. Since 3.5-beta1 -- Bugfixes. +- Bug fixes. - Full duplex audio with MAD16+CS4231 may work now. The driver configures SB DMA of MAD16 so that it doesn't conflict with codec's DMA channels. The side effect is that all 8 bit DMA channels (0,1,3) are populated in duplex mode. Since 3.5-alpha9 -- Bugfixes (mostly in Jazz16 and ESS1688/688 supports). +- Bug fixes (mostly in Jazz16 and ESS1688/688 supports). - Temporarily disabled recording with ESS1688/688 since it causes crash. - Changed audio buffer partitioning algorithm so that it selects smaller fragment size than earlier. This improves real time capabilities @@ -63,7 +116,7 @@ shorter than 4096 bytes. Since 3.5-alpha8 -- Bugfixes +- Bug fixes Since 3.5-alpha7 - Linux kernel compatible configuration (_EXPERIMENTAL_). Enable @@ -95,7 +148,7 @@ sources. Running 'setfx' is required again. Since 3.5-alpha3 -- Moved stuff from the 'setfx' program to the AudioTriX Pro driver. +- Moved stuff from the 'setfx' program to the AudioTrix Pro driver. Since 3.5-alpha2 - Modifications to makefile and configure.c. Unnecessary sources @@ -233,13 +286,13 @@ Since 2.2b - Full SB16 DSP support. 8/16 bit, mono/stereo - The SCO and FreeBSD versions should be in sync now. There are some - problems with SB16 and GUS in the freebsd versions. + problems with SB16 and GUS in the FreeBSD versions. The DMA buffer allocation of the SCO version has been polished but there could still be some problems. At least it hogs memory. The DMA channel - configuration method used in the sco/System is a hack. + configuration method used in the SCO/System is a hack. - Support for the MPU emulation of the SB16. -- Some big arrays are now allocated boot time. This makes the bss segment +- Some big arrays are now allocated boot time. This makes the BSS segment smaller which makes it possible to use the full driver with NetBSD. These arrays are not allocated if no suitable soundcard is available. - Fixed a bug in the compute_and_set_volume in gus_wave.c diff -ur --new-file old/linux/drivers/sound/COPYING new/linux/drivers/sound/COPYING --- old/linux/drivers/sound/COPYING Sun Mar 24 21:49:45 1996 +++ new/linux/drivers/sound/COPYING Sun Jun 30 10:43:45 1996 @@ -1,25 +1,339 @@ -/* - * Copyright by Hannu Savolainen 1993-1996 - * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff -ur --new-file old/linux/drivers/sound/Config.in new/linux/drivers/sound/Config.in --- old/linux/drivers/sound/Config.in Tue Jun 4 08:55:10 1996 +++ new/linux/drivers/sound/Config.in Tue Aug 20 16:38:55 1996 @@ -2,11 +2,16 @@ # Sound driver configuration # #-------- -# There is another config script which is compatible with rest of +# There is another confic script which is compatible with rest of # the kernel. It can be activated by running 'make mkscript' in this # directory. Please note that this is an _experimental_ feature which -# doesn't work with all cards (PSS, SM Wave, AudioTriX Pro). +# doesn't work with all cards (PSS, SM Wave, AudioTriX Pro, Maui). #-------- # $MAKE -C drivers/sound config || exit 1 +bool 'Additional low level drivers' CONFIG_LOWLEVEL_SOUND + +if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then + bool 'ACI mixer (miroPCM12)' CONFIG_ACI_MIXER +fi diff -ur --new-file old/linux/drivers/sound/Config.std new/linux/drivers/sound/Config.std --- old/linux/drivers/sound/Config.std Fri Apr 12 08:49:42 1996 +++ new/linux/drivers/sound/Config.std Sat Jul 6 10:31:43 1996 @@ -5,8 +5,13 @@ # There is another config script which is compatible with rest of # the kernel. It can be activated by running 'make mkscript' in this # directory. Please note that this is an _experimental_ feature which -# doesn't work with all cards (PSS, SM Wave, AudioTriX Pro). +# doesn't work with all cards (PSS, SM Wave, AudioTrix Pro, Maui). #-------- # $MAKE -C drivers/sound config || exit 1 +bool 'Additional low level drivers' CONFIG_LOWLEVEL_SOUND + +if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then + bool 'ACI mixer (miroPCM12)' CONFIG_ACI_MIXER +fi diff -ur --new-file old/linux/drivers/sound/Makefile new/linux/drivers/sound/Makefile --- old/linux/drivers/sound/Makefile Fri Jun 7 10:58:11 1996 +++ new/linux/drivers/sound/Makefile Sun Jun 30 10:43:41 1996 @@ -5,6 +5,8 @@ # # +.PHONY: dummy +SUB_DIRS = lowlevel VERSION = `head -1 .version` TARGET_OS = linux USRINCDIR = /usr/include @@ -12,17 +14,15 @@ FIXEDOBJS = soundcard.o dev_table.o sound_switch.o +ifndef NO_LOWLEVEL + FIXEDOBJS := $(FIXEDOBJS) lowlevel/lowlevel.o +endif + ifeq (.defines,$(wildcard .defines)) include .defines include .objects else -OBJS = audio.o dmabuf.o sb_dsp.o \ - opl3.o sequencer.o midibuf.o sb_card.o pas2_card.o adlib_card.o \ - pas2_pcm.o pas2_mixer.o pas2_midi.o gus_card.o gus_wave.o mpu401.o \ - gus_midi.o gus_vol.o patmgr.o sb_mixer.o sb16_dsp.o sb_midi.o \ - sb16_midi.o midi_synth.o uart6850.o sound_timer.o \ - sys_timer.o ics2101.o ad1848.o pss.o sscape.o trix.o aedsp16.o \ - mad16.o mad16_sb_midi.o cs4232.o maui.o +OBJS = `cat .object_files` endif ifndef TOPDIR @@ -59,7 +59,7 @@ # CC = gcc HOSTCC = gcc -CFLAGS = -D__KERNEL__ -DMODULE -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -m486 +CFLAGS = -O2 -D__KERNEL__ -DMODULE -I/usr/src/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -pipe -m486 USE_DEPEND=y else include $(TOPDIR)/Rules.make @@ -72,7 +72,8 @@ clean: rm -f core core.* *.o *.a tmp_make *~ x y z *% - rm -f configure sound_stub.c objects/*.o + rm -f configure sound_stub.c objects/*.o + cd lowlevel;make clean indent: for n in *.c;do echo indent $$n;indent $$n;done @@ -85,9 +86,9 @@ @echo @echo @echo - @echo "NOTE! Object file dependencies may not be up to date. Run" - @echo "make again if kernel/driver doesn't link properly. Restarting" - @echo "it now may save some time." + @echo NOTE! Object file dependencies may not be up to date. Run + @echo make again if kernel/driver doesn''t link properly. Restarting + @echo it now may save some time. @echo @echo @@ -108,7 +109,9 @@ # @echo \#define SOUND_CONFIG_DOMAIN \"`hostname -d`\" >> local.h 2>/dev/null @echo \#define SOUND_UNAME_A \"`uname -a`\" >> local.h -kernelconfig: setup-$(TARGET_OS) configure +kernelconfig: setup-$(TARGET_OS) + rm -f configure + $(HOSTCC) -o configure configure.c ./configure fixedlocal > local.h ./configure fixeddefines > .defines @echo \#define SOUND_CONFIG_DATE \"`date`\" >> local.h @@ -117,13 +120,16 @@ # @echo \#define SOUND_CONFIG_DOMAIN \"`hostname -d`\" >> local.h 2>/dev/null @echo \#define SOUND_UNAME_A \"`uname -a`\" >> local.h -mkscript: setup-$(TARGET_OS) configure +mkscript: setup-$(TARGET_OS) + rm -f configure + $(HOSTCC) -o configure configure.c ./configure script > Config.in + cat lowlevel/Config.tmpl >> Config.in ./configure fixedlocal > local.h ./configure fixeddefines > .defines clrconf: - rm -f local.h .depend synth-ld.h trix_boot.h smw-midi0001.h .defines + rm -f local.h .depend synth-ld.h trix_boot.h smw-midi0001.h maui_boot.h .defines configure: configure.c $(HOSTCC) -o configure configure.c @@ -142,6 +148,9 @@ modules: local.h sound.o ln -fs `pwd`/sound.o $(TOPDIR)/modules/sound.o + +lowlevel/lowlevel.o: dummy + cd lowlevel;make ifdef USE_DEPEND # diff -ur --new-file old/linux/drivers/sound/Readme new/linux/drivers/sound/Readme --- old/linux/drivers/sound/Readme Fri Apr 12 08:49:42 1996 +++ new/linux/drivers/sound/Readme Sat Jul 6 10:31:43 1996 @@ -1,29 +1,31 @@ -Version 3.5.2 release notes --------------------------------- +USS Lite version 3.5.4 release notes +------------------------------------ Most up to date information about this driver is available from -http://personal.eunet.fi/pp/voxware. +http://www.4front-tech.com/usslite or http://personal.eunet.fi/pp/voxware +(European mirror). - -Please read the SOUND-HOWTO (available from sunsite.unc.edu and other Linux ftp +Please read the SOUND-HOWTO (available from sunsite.unc.edu and other Linux FTP sites). It gives instructions about using sound with Linux. It's bit out of date but still very useful. Information about bug fixes and such things is available from the web page (see below). -New Programmer's Guide is currently under work (Feb/March 96). Please -check http://personal.eunet.fi/pp/voxware for more info. +New Programmer's Guide is currently under work (June/July 96). Please +check http://www.4front-tech.com/pguide for more info. ==================================================== - THIS VERSION ____REQUIRES____ Linux 1.3.70 OR LATER. ==================================================== It's very likely that this driver version is incompatible with -Linux versions later than 2.x. +Linux versions later than 2.0.x. Packages "snd-util-3.5.tar.gz" and "snd-data-0.1.tar.Z" contain useful utilities to be used with this driver. +See http://www.4front-tech.com/usslite/getting.html for +download instructions. If you are looking for the installation instructions, please look at Readme.linux. @@ -33,7 +35,7 @@ See Readme.cards. -Please check http://personal.eunet.fi/pp/voxware if you don't find +Please check http://www.4front-tech.com/usslite if you don't find your soundcard there. Contributors @@ -52,10 +54,10 @@ Andy Warner ISC port Jim Lowe, Amancio Hasty Jr FreeBSD/NetBSD port - Anders Baekgaard Bughunting and valuable suggestions. - Joerg Schubert SB16 DSP support. + Anders Baekgaard Bug hunting and valuable suggestions. + Joerg Schubert SB16 DSP support (initial version). Andrew Robinson Improvements to the GUS driver - Megens SA MIDI recording for SB and SB Pro. + Megens SA MIDI recording for SB and SB Pro (initial version). Mikael Nordqvist Linear volume support for GUS and nonblocking /dev/sequencer. Ian Hartas SVR4.2 port @@ -63,14 +65,16 @@ Risto Kankkunen Major contributions to the mixer support of GUS v3.7. Hunyue Yau Mixer support for SG NX Pro. - Marc Hoffman PSS support. - Rainer Vranken Initialization for Jazz16 (ProSonic, MV3D, SM Wave). + Marc Hoffman PSS support (initial version). + Rainer Vranken Initialization for Jazz16 (initial version). Peter Trattler Initial version of loadable module support for Linux. - JRA Gibson 16 bit mode for Jazz16 - Davor Jadrijevic MAD16 support - Gregor Hoffleit Mozart support + JRA Gibson 16 bit mode for Jazz16 (initial version) + Davor Jadrijevic MAD16 support (initial version) + Gregor Hoffleit Mozart support (initial version) Riccardo Facchetti Audio Excel DSP 16 (aedsp16) support James Hightower Spotting a tiny but important bug in CS423x support. + + Please look at lowlevel/README for more contributors. There are probably many other names missing. If you have sent me some patches and your name is not in the above list, please inform me. @@ -84,7 +88,7 @@ Novell, Inc. UnixWare personal edition + SDK The Santa Cruz Operation, Inc. A SCO OpenServer + SDK Ensoniq Corp, a SoundScape card and extensive amount of assistance -MediaTriX Peripherals Inc, a AudioTriX Pro card + SDK +MediaTrix Peripherals Inc, a AudioTrix Pro card + SDK Acer, Inc. a pair of AcerMagic S23 cards. In addition the following companies have provided me sufficient amount @@ -99,6 +103,8 @@ Integrated Circuit Systems Inc. OAK Technology OPTi +Turtle Beach +miro Ad Lib Inc. ($$) Music Quest Inc. ($$) Creative Labs ($$$) @@ -107,7 +113,7 @@ ========================= Read the sound HOWTO (sunsite.unc.edu:/pub/Linux/docs/...?). -Also look at the home page (http://personal.eunet.fi/pp/voxware). It may +Also look at the home page (http://www.4front-tech.com/usslite). It may contain info about some recent bug fixes. It's likely that you have some problems when trying to use the sound driver @@ -127,7 +133,7 @@ the sound driver are missing. Use the script at the end of linux/drivers/sound/Readme.linux to create them. - - "No such device" shows that the sound driver is not in the kernel. + - "No such device" tells that the sound driver is not in the kernel. You have to reconfigure and recompile the kernel to have the sound driver. Compiling the driver doesn't help alone. You have to boot with the newly compiled one before the driver becomes active. @@ -161,8 +167,8 @@ Hannu Hannu Savolainen -hannu@voxware.pp.fi -(Please check http:/personal.eunet.fi/pp/voxware before mailing me). +hannu@voxware.pp.fi, hannu@4front-tech.com +(Please check http://www.4front-tech.com/usslite before mailing me). Snail mail: Hannu Savolainen Hiekkalaiturintie 3 A 8 diff -ur --new-file old/linux/drivers/sound/Readme.aedsp16 new/linux/drivers/sound/Readme.aedsp16 --- old/linux/drivers/sound/Readme.aedsp16 Sun Mar 24 21:49:46 1996 +++ new/linux/drivers/sound/Readme.aedsp16 Mon Jul 15 08:55:11 1996 @@ -1,6 +1,6 @@ -Informations about Audio Excel DSP 16 can be found in the source +Information about Audio Excel DSP 16 can be found in the source file aedsp16.c Please, read the head of the source before using it. It contain useful -informations. +information. Riccardo diff -ur --new-file old/linux/drivers/sound/Readme.cards new/linux/drivers/sound/Readme.cards --- old/linux/drivers/sound/Readme.cards Mon May 6 11:26:11 1996 +++ new/linux/drivers/sound/Readme.cards Sat Jul 6 10:31:43 1996 @@ -1,40 +1,57 @@ -Configuring version 3.5 (for Linux) with some most common soundcards -==================================================================== +Configuring version 3.5.4 (for Linux) with some most common soundcards +====================================================================== IMPORTANT! This document covers only cards that were "known" when this driver version was released. Please look at - http://personal.eunet.fi/pp/voxware for info about + http://www.4front-tech.com/usslite for info about cards introduced recently. + The following covers mainly the "old" configuration + method (make config). Most of it is valid for the "new" + configuration (make menuconfig/xconfig) too. + + Cards having some kind of loadable "microcode" such as + PSS, SM Wave, AudioTrix Pro and Maui/Tropez must be + configured using the old method. The new one will not + work with them. + + When using make xconfig and/or make menuconfig, you should + carefully check each sound configuration option (particularly + "Support for /dev/dsp and /dev/audio"). + Cards that are not (fully) supported by this driver --------------------------------------------------- There are many soundcards which don't work with this driver version (v3.5). Support for some of them is expected to be available during/after summer 1996 (in version 3.6). Please check -http://personal.eunet.fi/pp/voxware for latest news. Please don't +http://www.4front-tech.com/usslite for latest news. Please don't mail me and ask about these cards. The unsupported cards are: - All PnP soundcards (SB PnP, GUS PnP, Soundscape PnP etc.) - (SB PnP in first 3.6-alpha version (Apr 96?), GUS PnP bit later, - Soundscape PnP probably much later, others ???). See - "Configuring PnP soundcards" below for some hints. + Schedule for availability of PnP soundcard support in + USS/Lite depends on progress made by kernel PnP team + (probably in Linux 2.1.xx versions). With Linux 2.0.x + versions there are two ways to get PnP soundcards to work: + - Use isapnptools, DOS, Win95 or PnP aware BIOS to wake up the + card before starting the sound driver. See "Configuring PnP + soundcards" below for some hints. + - Support for SB PnP and GUS PnP is present in USS/Linux (the + commercial version of this driver). - Mwave soundcards and motherboards - (Version 3.6 or 3.7. Depends on how fast I get a Mwave - card and suitable documents for it). + (Version 3.6 or 3.7. Depends on how fast I get + suitable documents for Mwave). - Emu8k (SB 32/AWE) - (Probably not before Nov/Dec 96. I know the unofficial + (Probably not _before_ summer 97. I know the unofficial AWE programmers guide so don't send me more copies of it). - Diamond Edge 3D (ASAP. In practice this may take relatively long time). - Compaq Deskpro - (Version 3.6???) - - Miro soundcards - (Early 3.6-alpha versions) - - OPTi 82C930 based soundcards - (Early 3.6-alpha versions?) + (Version 3.5.4-beta6 (already released)) - Sound Galaxy Washington/Waverider - (3.6-alpha versions. Can't promise the waverider synth). + (Audio features already in USS/Linux (USS/Lite soon). + Can't promise the waverider synth since + availability of chip specs is uncertain). - Yamaha OPL4 (on cards having _RAM_ for samples) (Late 96?. Works as OPL3 with current driver versions) @@ -53,14 +70,14 @@ Currently at least cards made by Creative Technology (SB32 and SB32AWE PnP), Gravis (GUS PnP and GUS PnP Pro), Ensoniq (Soundscape PnP) and Aztech (some Sound Galaxy models) use PnP technology. The CS4232 audio -chip by Crystal Semiconductor (Intel Atlantis, HP Pavillon and many other +chip by Crystal Semiconductor (Intel Atlantis, HP Pavilion and many other motherboards) is also based on PnP technology but there is a "native" driver available for it (see information about CS4232 later in this document). PnP soundcards (as well as most other PnP ISA cards) are not supported by version 3.5 of this driver (Linux 1.3.xx and Linux 2.0.x). Proper support for them should be released during spring 96 -(see http://personal.eunet.fi/pp/voxware for latest info). +(see http://www.4front-tech.com/usslite for latest info). There is a method to get most of the PnP cards to work. The basic method is the following: @@ -87,7 +104,11 @@ of such tool available from ftp://ftp.demon.co.uk/pub/unix/linux/utils. The file is called isapnptools-*. Please note that this tool is just a temporary solution which may be incompatible with future kernel versions having proper -support for PnP cards. +support for PnP cards. There are bugs in setting DMA channels in earlier +versions of isapnptools so at least version 1.6 is required with soundcards. +You can find latest version of isapnptools from +ftp://ftp.demon.co.uk/pub/unix/linux/utils/ + These two methods don't work with GUS PnP which requires some additional initialization (cards DOS/Win95 driver does it). @@ -154,7 +175,7 @@ (AD1848 by Analog Devices and CS4231/CS4248 by Crystal Semiconductor). Currently most soundcards are based on one of the MSS compatible codec chips. The CS4231 is used in the high quality cards such as GUS MAX, - MediaTriX AudioTriX Pro and TB Tropez (GUS MAX is not MSS compatible). + MediaTrix AudioTrix Pro and TB Tropez (GUS MAX is not MSS compatible). Having a AD1848, CS4248 or CS4231 codec chip on the card is a good sign. Even if the card is not MSS compatible, it could be easy to write @@ -177,7 +198,7 @@ voices than the OPL2. The OPL4 is a new chip that has an OPL3 and a wave table synthesizer packed onto the same chip. The driver supports just the OPL3 mode directly. Most cards with an OPL4 (like - SM Wave and AudioTriX Pro) support the OPL4 mode using MPU401 + SM Wave and AudioTrix Pro) support the OPL4 mode using MPU401 emulation. Writing a native OPL4 support is difficult since Yamaha doesn't give information about their sample ROM chip. @@ -195,7 +216,7 @@ The driver supports downloading DSP algorithms to these cards. -MediaTriX AudioTriX Pro +MediaTrix AudioTrix Pro The ATP card is built around a CS4231 codec and an OPL4 synthesizer chips. The OPL4 mode is supported by a microcontroller running a General MIDI emulator. There is also a SB 1.5 compatible playback mode. @@ -209,14 +230,15 @@ NOTE! The new PnP SoundScape is not supported yet. MAD16 and Mozart based cards - The Mozart (OAK OTI-601) and MAD16 Pro (OPTi 82C929) interface + The Mozart (OAK OTI-601), MAD16 (OPTi 82C928), MAD16 Pro (OPTi 82C929) + and OPTi 82C930 interface chips are used in many different soundcards, including some - cards by Reveal and Turtle Beach (Tropez). The purpose of these + cards by Reveal miro and Turtle Beach (Tropez). The purpose of these chips is to connect other audio components to the PC bus. The interface chip performs address decoding for the other chips. NOTE! Tropez Plus is not MAD16 but CS4232 based. -Audio Excell DSP16 +Audio Excel DSP16 Support for this card was written by Riccardo Faccetti (riccardo@cdc8g5.cdc.polimi.it). See aedsp16.c for more info. (This driver is not functional in version 3.5 of this driver. A @@ -362,7 +384,7 @@ "ProAudioSpectrum 16 support", - Answer 'y'_ONLY_ if you have a Pro Audio Spectrum _16_, - ProAudio Studio 16 or Logitech SoundMan 16 (be sure that + Pro Audio Studio 16 or Logitech SoundMan 16 (be sure that you read the above list correctly). Don't answer 'y' if you have some other card made by Media Vision or Logitech since they are not PAS16 compatible. @@ -370,7 +392,7 @@ if you want to use the SB emulation of PAS16. It's also possible to the emulation if you want to use a true SB card together with PAS16 (there is another question about this that is asked later). - "SoundBlaster support", + "Sound Blaster support", - Answer 'y' if you have an original SB card made by Creative Labs or a full 100% hardware compatible clone (like Thunderboard or SM Games). If your card was in the list of supported cards (above), @@ -428,11 +450,11 @@ - Answer 'y' if you have a soundcard based on the Ensoniq SoundScape chipset. Such cards are being manufactured at least by Ensoniq, Spea and Reveal (note that Reveal makes other cards also). - "MediaTriX AudioTriX Pro support", - - Answer 'y' if you have the AudioTriX Pro. + "MediaTrix AudioTrix Pro support", + - Answer 'y' if you have the AudioTrix Pro. "Support for MAD16 and/or Mozart based cards", - Answer y if your card has a Mozart (OAK OTI-601) or MAD16 - (OPTi 82C928 or 82C929) audio interface chip. These chips are + (OPTi 82C928, 82C929 or 82C930) audio interface chip. These chips are currently quite common so it's possible that many no-name cards have one of them. In addition the MAD16 chip is used in some cards made by known manufacturers such as Turtle Beach (Tropez), @@ -483,7 +505,7 @@ different values could cause some problems when switching between different operating systems. -SoundBlasters (the original ones by Creative) +Sound Blasters (the original ones by Creative) --------------------------------------------- It's possible to configure these cards to use different I/O, IRQ and @@ -607,7 +629,7 @@ will fail. GUS PnP (with RAM) is partially supported but it needs to be initialized using -DOS before booting Linux. This may fail on machines having PnP BIOS. +DOS or isapnptools before starting the driver. MPU401 and Windows Sound System ------------------------------- @@ -655,11 +677,11 @@ It's possible to load your own DSP algorithms and run them with the card. Look at the directory pss_test of snd-util-3.0.tar.gz for more info. -AudioTriX Pro +AudioTrix Pro ------------- You have to enable the OPL3 and SB (not SB Pro or SB16) drivers in addition -to the native AudioTriX driver. Don't enable MSS or MPU drivers. +to the native AudioTrix driver. Don't enable MSS or MPU drivers. Configuring ATP is little bit tricky since it uses so many I/O, IRQ and DMA numbers. Using the same values than with DOS/Win is a good idea. Don't @@ -689,22 +711,27 @@ itself so you don't need to enable other drivers than SoundScape (enable also the /dev/dsp, /dev/sequencer and MIDI supports). -SoundScape driver uses the MSS compatible codec of the card. It's important -to note that /dev/dsp0 (/dev/dsp is linked to /dev/dsp0 by default) -doesn't work with SoundScape (yet). The 'ssinit' program needs /dev/dsp0 so -that's the reason why it's there. It's possible that 'primary' pcm channel -becomes supported later. Currently the card's firmware doesn't contain -support for it. - -With 3.0 of the driver you have to change your system to use /dev/dsp1 by default -so execute: cd /dev;rm dsp;ln -s dsp1 dsp after you have installed driver -version 3.0 (or later) first time. +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +!!!!! !!!! +!!!!! NOTE! Before version 3.5-beta6 there WERE two sets of audio !!!! +!!!!! device files (/dev/dsp0 and /dev/dsp1). The first one WAS !!!! +!!!!! used only for card initialization and the second for audio !!!! +!!!!! purposes. It WAS required to change /dev/dsp (a symlink) to !!!! +!!!!! point to /dev/dsp1. !!!! +!!!!! !!!! +!!!!! This is not required with USS versions 3.5-beta6 and later !!!! +!!!!! since there is now just one audio device file. Please !!!! +!!!!! change /dev/dsp to point back to /dev/dsp0 if you are !!!! +!!!!! upgrading from an earlier driver version using !!!! +!!!!! (cd /dev;rm dsp;ln -s dsp0 dsp). !!!! +!!!!! !!!! +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -The configuration program asks two DMA channels and two interrupts. One IRQ +The configuration program asks one DMA channel and two interrupts. One IRQ and one DMA is used by the MSS codec. The second IRQ is required for the MPU401 mode (you have to use different IRQs for both purposes). -The second DMA channel is required for initialization of the microcontroller. -You have to use separate DMA channels. +There were earlier two DMA channels for SoundScape but the current driver +version requires just one. The SoundScape card has a Motorola microcontroller which must initialized _after_ boot (the driver doesn't initialize it during boot). @@ -727,7 +754,8 @@ and locate the sound driver initialization message for the SoundScape card. If the driver displays string , you have an old card and you will need to use sndscape.co1. For other cards use -soundscape.co0. +soundscape.co0. New Soundscape revisions such as Elite and PnP use +code files with higher numbers (.co2, .co3, etc.). Check /var/adm/messages after running ssinit. The driver prints the board version after downloading the microcode file. That version @@ -749,7 +777,8 @@ Mozart and OPTi 82C928 (the original MAD16) chips don't support MPU401 mode so enter just 0 when the configuration program asks the -MPU/MIDI I/O base. The MAD16 Pro (OPTi 82C929) has MPU401 mode. +MPU/MIDI I/O base. The MAD16 Pro (OPTi 82C929) and 82C930 chips have MPU401 +mode. TB Tropez is based on the 82C929 chip. It has two MIDI ports. The one connected to the MAD16 chip is the second one (there is a second @@ -765,7 +794,7 @@ this should not be a problem. If you have a MAD16 card which have an OPL4 (FM + Wave table) synthesizer -chip (_not_ an OPL3), you have to append line containing #define MAD16_OPL4 +chip (_not_ an OPL3), you have to append a line containing #define MAD16_OPL4 to the file linux/drivers/sound/local.h (after running make config). MAD16 cards having a CS4231 codec support full duplex mode. This mode @@ -836,8 +865,8 @@ ESS ES1688 and ES688 'AudioDrive' based cards --------------------------------------------- -Support for these two ESS chips is embedded in the SB Pro driver. -Configure these cards just like SB Pro. Enable the 'SB MPU401 MIDI port' +Support for these two ESS chips is embedded in the SB driver. +Configure these cards just like SB. Enable the 'SB MPU401 MIDI port' if you want to use MIDI features of ES1688. ES688 doesn't have MPU mode so you don't need to enable it (the driver uses normal SB MIDI automatically with ES688). @@ -879,6 +908,53 @@ configuring Linux. Having it enabled is likely to cause mysterious problems and kernel failures when sound is used. +miroSOUND +--------- + +The miroSOUND PCM12 has been used successfully. This card is based on +the MAD16, OPL4, and CS4231A chips and everything said in the section +about MAD16 cards applies here, too. The only major difference between +the PCM12 and other MAD16 cards is that instead of the mixer in the +CS4231 codec a separate mixer controlled by an on-board 80C32 +microcontroller is used. Control of the mixer takes place via the ACI +(miro's audio control interface) protocol that is implemented in a +separate lowlevel driver. Make sure you compile this ACI driver +together with the normal MAD16 support when you use a miroSOUND PCM12 +card. The ACI mixer is controlled by /dev/mixer and the CS4231 mixer +by /dev/mixer2. You usually don't want to change anything on the +CS4231 mixer. + +The miroSOUND PCM12 is capable of full duplex operation (simultaneous +PCM replay and recording), which allows you to implement nice +real-time signal processing audio effect software and network +telephones. The ACI mixer has to be configured into a special "solo" +mode for duplex operation in order to avoid feedback caused by the +mixer (input hears output signal). See lowlevel/aci.c for details on +the ioctl() for activating the "solo" mode. + +The following configuration parameters have worked fine for the PCM12 +in Markus Kuhn's system, many other configurations might work, too: +MAD16_BASE=0x530, MAD16_IRQ=11, MAD16_DMA=3, MAD16_DMA2=0, +MAD16_MPU_BASE=0x330, MAD16_MPU_IRQ=10, DSP_BUFFSIZE=65536, +SELECTED_SOUND_OPTIONS=0x00281000. + +The miroSOUND PCM1 pro and the PCM20 are very similar to the PCM12. +Perhaps the same ACI driver also works for these cards, however this +has never actually been tested. The PCM20 contains a radio tuner, +which is also controlled by ACI. This radio tuner is currently not +supported by the ACI driver, but documentation for it was provided by +miro and ACI tuner support could easily be added if someone is really +interested. + +Compaq Deskpro XL +----------------- + +The builtin sound hardware of Compaq Deskpro XL is now supported. +You need to configure the driver with MSS and OPL3 supports enabled. +In addition you need to manually edit linux/drivers/sound/local.h and +to add a line containing "#define DESKPROXL" if you used +make menuconfig/xconfig. + Others? ------- @@ -896,7 +972,7 @@ introduced. Driver's release date is listed after its version number in "cat /dev/sndstat" printout and in file linux/drivers/sound/soundvers.h. -First of all, there is an easy way to make most soundcards to work +First of all. There is an easy way to make most soundcards to work with Linux. Just use the DOS based driver to initialize the card to a _known_ state. Then use loadlin.exe to boot Linux. If Linux is configured to use the same I/O, IRQ and DMA numbers than DOS, the card could work. @@ -923,7 +999,7 @@ Writing a driver for a new card is not possible if there are no programming information available about the card. If you don't find your new card from this file, look from the home page -(http://personal.eunet.fi/pp/voxware). Then please contact +(http://www.4front-tech.com/usslite). Then please contact manufacturer of the card and ask if they have (or are willing to) released technical details of the card. Do this before contacting me. I can only answer 'no' if there are no programming information available. @@ -944,7 +1020,7 @@ There are some common audio chipsets that are not supported yet. For example Sierra Aria and IBM Mwave. It's possible that these architectures get some support in future but I can't make any promises. Just look -at the home page (http://personal.eunet.fi/pp/voxware/new_cards.html) +at the home page (http://www.4front-tech.com/usslite/new_cards.html) for latest info. Information about unsupported soundcards and chipsets is welcome as well @@ -954,6 +1030,11 @@ Hannu Savolainen hannu@voxware.pp.fi -Sound driver's www home page: http://personal.eunet.fi/pp/voxware - US mirror: http://www.4Front-Tech.com/usslite + +Personal home page: http://personal.eunet.fi/pp/voxware/hannu.html +www home page of USS/Lite: http://www.4front-tech.com/usslite + European/Finnish mirror: http://personal.eunet.fi/pp/voxware + +www home page of commercial +UNIX Sound System drivers: http://www.4front-tech.com/uss.html diff -ur --new-file old/linux/drivers/sound/Readme.linux new/linux/drivers/sound/Readme.linux --- old/linux/drivers/sound/Readme.linux Mon May 27 13:07:55 1996 +++ new/linux/drivers/sound/Readme.linux Sat Jul 6 10:31:43 1996 @@ -67,7 +67,7 @@ check for possible boot (insmod) time error messages in /var/adm/messages. - Other messages or problems -Please check http://personal.eunet.fi/pp/voxware for more info. +Please check http://www.4front-tech.com/usslite for more info. Hannu Savolainen hannu@voxware.pp.fi diff -ur --new-file old/linux/drivers/sound/Readme.v30 new/linux/drivers/sound/Readme.v30 --- old/linux/drivers/sound/Readme.v30 Fri Apr 12 08:49:42 1996 +++ new/linux/drivers/sound/Readme.v30 Sat Jul 6 10:31:43 1996 @@ -124,7 +124,7 @@ - The basic API usage is similar to the current one. There are some new macros but the older ones should work as earlier. The most important incompatibility is that the /dev/sequencer2 driver allocates voices itself. -The other one is that the application must send SEQ_START_TIMER() as it's +The other one is that the application must send SEQ_START_TIMER() as its first event. Otherwise the timer is not started and the application waits infinitely. diff -ur --new-file old/linux/drivers/sound/ad1848.c new/linux/drivers/sound/ad1848.c --- old/linux/drivers/sound/ad1848.c Mon May 6 11:26:12 1996 +++ new/linux/drivers/sound/ad1848.c Sun Aug 18 09:46:48 1996 @@ -15,27 +15,11 @@ */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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 @@ -64,16 +48,18 @@ unsigned char format_bits; int xfer_count; - int irq_mode; + int audio_mode; int intr_active; int opened; char *chip_name; - int mode; + int model; #define MD_1848 1 #define MD_4231 2 #define MD_4231A 3 #define MD_1845 4 #define MD_4232 5 +#define MD_C930 6 +#define MD_IWAVE 7 /* Mixer parameters */ int recmask; @@ -96,16 +82,15 @@ static int timer_installed = -1; -static char mixer2codec[MAX_MIXER_DEV] = -{0}; - -static int ad_format_mask[6 /*devc->mode */ ] = +static int ad_format_mask[8 /*devc->model */ ] = { 0, AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW, AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM, AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM, AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW, /* AD1845 */ + AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM, + AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM, AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_U16_LE | AFMT_IMA_ADPCM }; @@ -121,6 +106,7 @@ static int ad1848_ioctl (int dev, unsigned int cmd, caddr_t arg, int local); static void ad1848_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart); static void ad1848_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart); +static int ad1848_prepare_for_output (int dev, int bsize, int bcount); static int ad1848_prepare_for_IO (int dev, int bsize, int bcount); static void ad1848_reset (int dev); static void ad1848_halt (int dev); @@ -196,7 +182,8 @@ while (timeout > 0 && ad_read (devc, 11) & 0x20) timeout--; if (ad_read (devc, 11) & 0x20) - printk ("ad1848: Auto calibration timed out(3).\n"); + if (devc->model != MD_1845) + printk ("ad1848: Auto calibration timed out(3).\n"); } static void @@ -205,8 +192,6 @@ int i; unsigned char prev; - if (devc->mode != MD_1848) - return; /* * Save old register settings and mute output channels */ @@ -215,6 +200,12 @@ prev = devc->saved_regs[i] = ad_read (devc, i); ad_write (devc, i, prev | 0x80); } + +/* + * Let's have some delay + */ + for (i = 0; i < 1000; i++) + inb (devc->base); } static void @@ -222,6 +213,12 @@ { int i; +/* + * Let's have some delay + */ + for (i = 0; i < 1000; i++) + inb (devc->base); + /* * Restore back old volume registers (unmute) */ @@ -367,7 +364,7 @@ ad1848_mixer_get (ad1848_info * devc, int dev) { if (!((1 << dev) & devc->supported_devices)) - return -EINVAL; + return -(EINVAL); return devc->levels[dev]; } @@ -401,13 +398,13 @@ right = mix_cvt[right]; if (dev > 31) - return -EINVAL; + return -(EINVAL); if (!(devc->supported_devices & (1 << dev))) - return -EINVAL; + return -(EINVAL); if (mix_devices[dev][LEFT_CHN].nbits == 0) - return -EINVAL; + return -(EINVAL); devc->levels[dev] = retvol; @@ -442,10 +439,12 @@ { int i; - switch (devc->mode) + switch (devc->model) { case MD_4231: case MD_4231A: + case MD_C930: + case MD_IWAVE: case MD_1845: devc->supported_devices = MODE2_MIXER_DEVICES; break; @@ -469,16 +468,7 @@ static int ad1848_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) { - ad1848_info *devc; - - int codec_dev = mixer2codec[dev]; - - if (!codec_dev) - return -ENXIO; - - codec_dev--; - - devc = (ad1848_info *) audio_devs[codec_dev]->devc; + ad1848_info *devc = mixer_devs[dev]->devc; if (((cmd >> 8) & 0xff) == 'M') { @@ -487,11 +477,11 @@ switch (cmd & 0xff) { case SOUND_MIXER_RECSRC: - return snd_ioctl_return ((int *) arg, ad1848_set_recmask (devc, get_fs_long ((long *) arg))); + return snd_ioctl_return ((int *) arg, ad1848_set_recmask (devc, get_user ((int *) arg))); break; default: - return snd_ioctl_return ((int *) arg, ad1848_mixer_set (devc, cmd & 0xff, get_fs_long ((long *) arg))); + return snd_ioctl_return ((int *) arg, ad1848_mixer_set (devc, cmd & 0xff, get_user ((int *) arg))); } else switch (cmd & 0xff) /* @@ -524,118 +514,27 @@ } } else - return -EINVAL; + return -(EINVAL); } -static struct audio_operations ad1848_pcm_operations[MAX_AUDIO_DEV] = -{ - { - "Generic AD1848 codec", - DMA_AUTOMODE, - AFMT_U8, /* Will be set later */ - NULL, - ad1848_open, - ad1848_close, - ad1848_output_block, - ad1848_start_input, - ad1848_ioctl, - ad1848_prepare_for_IO, - ad1848_prepare_for_IO, - ad1848_reset, - ad1848_halt, - NULL, - NULL, - ad1848_halt_input, - ad1848_halt_output, - ad1848_trigger - }}; - -static struct mixer_operations ad1848_mixer_operations = -{ - "AD1848/CS4248/CS4231", - ad1848_mixer_ioctl -}; - static int -ad1848_open (int dev, int mode) +ad1848_set_speed (int dev, int arg) { - ad1848_info *devc = NULL; - unsigned long flags; - - if (dev < 0 || dev >= num_audiodevs) - return -ENXIO; - - devc = (ad1848_info *) audio_devs[dev]->devc; - - - save_flags (flags); - cli (); - if (devc->opened) - { - restore_flags (flags); - printk ("ad1848: Already opened\n"); - return -EBUSY; - } - - - devc->dual_dma = 0; - - if (audio_devs[dev]->flags & DMA_DUPLEX) - { - devc->dual_dma = 1; - } - - devc->intr_active = 0; - devc->opened = 1; - devc->irq_mode = 0; - ad1848_trigger (dev, 0); - restore_flags (flags); -/* - * Mute output until the playback really starts. This decreases clicking (hope so). - */ - ad_mute (devc); - - return 0; -} - -static void -ad1848_close (int dev) -{ - unsigned long flags; ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - DEB (printk ("ad1848_close(void)\n")); - - save_flags (flags); - cli (); - - devc->intr_active = 0; - ad1848_reset (dev); - - - devc->opened = 0; - devc->irq_mode = 0; - - ad_unmute (devc); - restore_flags (flags); -} - -static int -set_speed (ad1848_info * devc, int arg) -{ /* * The sampling speed is encoded in the least significant nibble of I8. The - * LSB selects the clock source (0=24.576 MHz, 1=16.9344 Mhz) and other + * LSB selects the clock source (0=24.576 MHz, 1=16.9344 MHz) and other * three bits select the divisor (indirectly): * * The available speeds are in the following table. Keep the speeds in * the increasing order. */ typedef struct - { - int speed; - unsigned char bits; - } + { + int speed; + unsigned char bits; + } speed_struct; static speed_struct speed_table[] = @@ -661,7 +560,10 @@ n = sizeof (speed_table) / sizeof (speed_struct); - if (devc->mode == MD_1845) /* AD1845 has different timer than others */ + if (arg == 0) + return devc->speed; + + if (devc->model == MD_1845) /* AD1845 has different timer than others */ { if (arg < 4000) arg = 4000; @@ -705,9 +607,11 @@ return devc->speed; } -static int -set_channels (ad1848_info * devc, int arg) +static short +ad1848_set_channels (int dev, short arg) { + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + if (arg != 1 && arg != 2) return devc->channels; @@ -715,15 +619,16 @@ return arg; } -static int -set_format (ad1848_info * devc, int arg) +static unsigned int +ad1848_set_bits (int dev, unsigned int arg) { + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; static struct format_tbl - { - int format; - unsigned char bits; - } + { + int format; + unsigned char bits; + } format2bits[] = { { @@ -768,7 +673,10 @@ }; int i, n = sizeof (format2bits) / sizeof (struct format_tbl); - if (!(arg & ad_format_mask[devc->mode])) + if (arg == 0) + return devc->audio_format; + + if (!(arg & ad_format_mask[devc->model])) arg = AFMT_U8; devc->audio_format = arg; @@ -787,51 +695,100 @@ return devc->audio_format = AFMT_U8; } +static struct audio_driver ad1848_audio_driver = +{ + ad1848_open, + ad1848_close, + ad1848_output_block, + ad1848_start_input, + ad1848_ioctl, + ad1848_prepare_for_IO, + ad1848_prepare_for_output, + ad1848_reset, + ad1848_halt, + NULL, + NULL, + ad1848_halt_input, + ad1848_halt_output, + ad1848_trigger, + ad1848_set_speed, + ad1848_set_bits, + ad1848_set_channels +}; + +static struct mixer_operations ad1848_mixer_operations = +{ + "SOUNDPORT", + "AD1848/CS4248/CS4231", + ad1848_mixer_ioctl +}; + static int -ad1848_ioctl (int dev, unsigned int cmd, caddr_t arg, int local) +ad1848_open (int dev, int mode) { - ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + ad1848_info *devc = NULL; + unsigned long flags; + + if (dev < 0 || dev >= num_audiodevs) + return -(ENXIO); + + devc = (ad1848_info *) audio_devs[dev]->devc; + - switch (cmd) + save_flags (flags); + cli (); + if (devc->opened) { - case SOUND_PCM_WRITE_RATE: - if (local) - return set_speed (devc, (int) arg); - return snd_ioctl_return ((int *) arg, set_speed (devc, get_fs_long ((long *) arg))); - - case SOUND_PCM_READ_RATE: - if (local) - return devc->speed; - return snd_ioctl_return ((int *) arg, devc->speed); - - case SNDCTL_DSP_STEREO: - if (local) - return set_channels (devc, (int) arg + 1) - 1; - return snd_ioctl_return ((int *) arg, set_channels (devc, get_fs_long ((long *) arg) + 1) - 1); - - case SOUND_PCM_WRITE_CHANNELS: - if (local) - return set_channels (devc, (int) arg); - return snd_ioctl_return ((int *) arg, set_channels (devc, get_fs_long ((long *) arg))); - - case SOUND_PCM_READ_CHANNELS: - if (local) - return devc->channels; - return snd_ioctl_return ((int *) arg, devc->channels); - - case SNDCTL_DSP_SAMPLESIZE: - if (local) - return set_format (devc, (int) arg); - return snd_ioctl_return ((int *) arg, set_format (devc, get_fs_long ((long *) arg))); - - case SOUND_PCM_READ_BITS: - if (local) - return devc->audio_format; - return snd_ioctl_return ((int *) arg, devc->audio_format); + restore_flags (flags); + return -(EBUSY); + } - default:; + devc->dual_dma = 0; + + if (audio_devs[dev]->flags & DMA_DUPLEX) + { + devc->dual_dma = 1; } - return -EINVAL; + + devc->intr_active = 0; + devc->opened = 1; + devc->audio_mode = 0; + ad1848_trigger (dev, 0); + restore_flags (flags); +/* + * Mute output until the playback really starts. This decreases clicking (hope so). + */ + ad_mute (devc); + + return 0; +} + +static void +ad1848_close (int dev) +{ + unsigned long flags; + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + + DEB (printk ("ad1848_close(void)\n")); + + save_flags (flags); + cli (); + + devc->intr_active = 0; + ad1848_reset (dev); + + + devc->opened = 0; + devc->audio_mode = 0; + + ad_unmute (devc); + restore_flags (flags); +} + +static int +ad1848_ioctl (int dev, unsigned int cmd, caddr_t arg, int local) +{ + return -(EINVAL); } static void @@ -840,6 +797,9 @@ unsigned long flags, cnt; ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + if (!dma_restart) + return; + cnt = count; if (devc->audio_format == AFMT_IMA_ADPCM) @@ -855,11 +815,11 @@ cnt >>= 1; cnt--; - if (devc->irq_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) { - devc->irq_mode |= PCM_ENABLE_OUTPUT; + devc->audio_mode |= PCM_ENABLE_OUTPUT; devc->intr_active = 1; return; /* * Auto DMA mode on. No need to react @@ -868,20 +828,16 @@ save_flags (flags); cli (); - if (dma_restart) - { - ad_write (devc, 9, ad_read (devc, 9) & ~0x01); /* Playback disable */ - /* ad1848_halt (dev); */ - DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); - } + /* ad_write (devc, 9, ad_read (devc, 9) & ~ 0x01); / * Playback disable */ + ad1848_halt (dev); + DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); ad_write (devc, 15, (unsigned char) (cnt & 0xff)); ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff)); - ad_unmute (devc); devc->xfer_count = cnt; - devc->irq_mode |= PCM_ENABLE_OUTPUT; + devc->audio_mode |= PCM_ENABLE_OUTPUT; devc->intr_active = 1; restore_flags (flags); } @@ -892,6 +848,9 @@ unsigned long flags, cnt; ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + if (!dma_restart) + return; + cnt = count; if (devc->audio_format == AFMT_IMA_ADPCM) { @@ -906,11 +865,11 @@ cnt >>= 1; cnt--; - if (devc->irq_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) { - devc->irq_mode |= PCM_ENABLE_INPUT; + devc->audio_mode |= PCM_ENABLE_INPUT; devc->intr_active = 1; return; /* * Auto DMA mode on. No need to react @@ -926,7 +885,7 @@ DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); } - if (devc->mode == MD_1848 || !devc->dual_dma) /* Single DMA channel mode */ + if (devc->model == MD_1848 || !devc->dual_dma) /* Single DMA channel mode */ { ad_write (devc, 15, (unsigned char) (cnt & 0xff)); ad_write (devc, 14, (unsigned char) ((cnt >> 8) & 0xff)); @@ -941,12 +900,22 @@ ad_unmute (devc); devc->xfer_count = cnt; - devc->irq_mode |= PCM_ENABLE_INPUT; + devc->audio_mode |= PCM_ENABLE_INPUT; devc->intr_active = 1; restore_flags (flags); } static int +ad1848_prepare_for_output (int dev, int bsize, int bcount) +{ + ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; + + ad_mute (devc); + + return ad1848_prepare_for_IO (dev, bsize, bcount); +} + +static int ad1848_prepare_for_IO (int dev, int bsize, int bcount) { int timeout; @@ -954,7 +923,7 @@ unsigned long flags; ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; - if (devc->irq_mode) + if (devc->audio_mode) return 0; save_flags (flags); @@ -964,7 +933,7 @@ if (devc->channels > 1) fs |= 0x10; - if (devc->mode == MD_1845) /* Use alternate speed select registers */ + if (devc->model == MD_1845) /* Use alternate speed select registers */ { fs &= 0xf0; /* Mask off the rate select bits */ @@ -974,7 +943,7 @@ old_fs = ad_read (devc, 8); - if (devc->mode != MD_4232) + if (devc->model != MD_4232) if (fs == old_fs) /* No change */ { restore_flags (flags); @@ -984,7 +953,7 @@ ad_enter_MCE (devc); /* Enables changes to the format select reg */ - if (devc->mode == MD_4232) + if (devc->model == MD_4232) { tmp = ad_read (devc, 16); ad_write (devc, 16, tmp | 0x30); @@ -999,9 +968,9 @@ timeout--; /* - * If mode == 2 (CS4231), set I28 also. It's the capture format register. + * If mode >= 2 (CS4231), set I28 also. It's the capture format register. */ - if (devc->mode != MD_1848) + if (devc->model != MD_1848) { ad_write (devc, 28, fs); @@ -1014,7 +983,7 @@ } - if (devc->mode == MD_4232) + if (devc->model == MD_4232) ad_write (devc, 16, tmp & ~0x30); ad_leave_MCE (devc); /* @@ -1064,7 +1033,7 @@ ad_mute (devc); - if (devc->mode == MD_4232) /* Use applied black magic */ + if (devc->model == MD_4232) /* Use applied black magic */ { int tmout; @@ -1085,7 +1054,7 @@ outb (0, io_Status (devc)); /* Clear interrupt status */ outb (0, io_Status (devc)); /* Clear interrupt status */ - devc->irq_mode &= ~PCM_ENABLE_INPUT; + devc->audio_mode &= ~PCM_ENABLE_INPUT; restore_flags (flags); } @@ -1100,7 +1069,7 @@ cli (); ad_mute (devc); - if (devc->mode == MD_4232) /* Use applied black magic */ + if (devc->model == MD_4232) /* Use applied black magic */ { int tmout; @@ -1121,7 +1090,7 @@ outb (0, io_Status (devc)); /* Clear interrupt status */ outb (0, io_Status (devc)); /* Clear interrupt status */ - devc->irq_mode &= ~PCM_ENABLE_OUTPUT; + devc->audio_mode &= ~PCM_ENABLE_OUTPUT; restore_flags (flags); } @@ -1131,35 +1100,62 @@ { ad1848_info *devc = (ad1848_info *) audio_devs[dev]->devc; unsigned long flags; - unsigned char tmp; + unsigned char tmp, old; save_flags (flags); cli (); - state &= devc->irq_mode; + state &= devc->audio_mode; - tmp = ad_read (devc, 9) & ~0x03; + tmp = (old = ad_read (devc, 9)) & ~0x03; if (state & PCM_ENABLE_INPUT) tmp |= 0x02; if (state & PCM_ENABLE_OUTPUT) tmp |= 0x01; + + if (!(state & PCM_ENABLE_OUTPUT) && old & 0x01); + ad_mute (devc); + ad_write (devc, 9, tmp); + if (state & PCM_ENABLE_OUTPUT && !(old & 0x01)); + ad_unmute (devc); + restore_flags (flags); } int ad1848_detect (int io_base, int *ad_flags, int *osp) { + /* + * Initial values for the indirect registers of CS4248/AD1848. + */ + static int init_values[] = + { + 0xa8, 0xa8, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, + 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, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; unsigned char tmp; ad1848_info *devc = &dev_info[nr_ad1848_devs]; unsigned char tmp1 = 0xff, tmp2 = 0xff; + int optiC930 = 0; /* OPTi 82C930 flag */ + int interwave = 0; + int ad1847_flag = 0; + int i; DDB (printk ("ad1848_detect(%x)\n", io_base)); if (ad_flags) - *ad_flags = 0; + { + if (*ad_flags == 0x12345678) + interwave = 1; + *ad_flags = 0; + } if (nr_ad1848_devs >= MAX_AUDIO_DEV) { @@ -1179,7 +1175,7 @@ devc->irq = 0; devc->opened = 0; devc->chip_name = "AD1848"; - devc->mode = MD_1848; /* AD1848 or CS4248 */ + devc->model = MD_1848; /* AD1848 or CS4248 */ devc->osp = osp; devc->debug_flag = 0; @@ -1187,7 +1183,7 @@ * Check that the I/O address is in use. * * The bit 0x80 of the base I/O port is known to be 0 after the - * chip has performed its power-on initialization. Just assume + * chip has performed its power on initialization. Just assume * this has happened before the OS is starting. * * If the I/O address is unused, it typically returns 0xff. @@ -1217,23 +1213,29 @@ ad_write (devc, 1, 0x45); /* 0x55 with bit 0x10 clear */ if ((tmp1 = ad_read (devc, 0)) != 0xaa || (tmp2 = ad_read (devc, 1)) != 0x45) - { - DDB (printk ("ad1848 detect error - step B (%x/%x)\n", tmp1, tmp2)); - return 0; - } + if (tmp2 == 0x65) /* AD1847 has couple of bits hardcoded to 1 */ + ad1847_flag = 1; + else + { + DDB (printk ("ad1848 detect error - step B (%x/%x)\n", tmp1, tmp2)); + return 0; + } DDB (printk ("ad1848_detect() - step C\n")); ad_write (devc, 0, 0x45); ad_write (devc, 1, 0xaa); if ((tmp1 = ad_read (devc, 0)) != 0x45 || (tmp2 = ad_read (devc, 1)) != 0xaa) - { - DDB (printk ("ad1848 detect error - step C (%x/%x)\n", tmp1, tmp2)); - return 0; - } + if (tmp2 == 0x8a) /* AD1847 has few bits hardcoded to 1 */ + ad1847_flag = 1; + else + { + DDB (printk ("ad1848 detect error - step C (%x/%x)\n", tmp1, tmp2)); + return 0; + } /* - * The indirect register I12 has some read only bits. Let's + * The indirect register I12 has some read only bits. Lets * try to change them. */ @@ -1259,6 +1261,22 @@ * with CS4231. */ +/* + * OPTi 82C930 has mode2 control bit in another place. This test will fail + * with it. Accept this situation as a possible indication of this chip. + */ + + DDB (printk ("ad1848_detect() - step F\n")); + ad_write (devc, 12, 0); /* Mode2=disabled */ + + for (i = 0; i < 16; i++) + if ((tmp1 = ad_read (devc, i)) != (tmp2 = ad_read (devc, i + 16))) + { + DDB (printk ("ad1848 detect step F(%d/%x/%x) - OPTi chip?\n", i, tmp1, tmp2)); + if (!ad1847_flag) + optiC930 = 1; + break; + } /* * Try to switch the chip to mode2 (CS4231) by setting the MODE2 bit (0x40). @@ -1277,7 +1295,7 @@ devc->chip_name = "CS4248"; /* Our best knowledge just now */ } - if ((tmp1 & 0xc0) == (0x80 | 0x40)) + if (optiC930 || (tmp1 & 0xc0) == (0x80 | 0x40)) { /* * CS4231 detected - is it? @@ -1314,7 +1332,7 @@ */ devc->chip_name = "CS4231"; - devc->mode = MD_4231; + devc->model = MD_4231; /* * It could be an AD1845 or CS4231A as well. @@ -1330,17 +1348,17 @@ case 0xa0: devc->chip_name = "CS4231A"; - devc->mode = MD_4231A; + devc->model = MD_4231A; break; case 0xa2: devc->chip_name = "CS4232"; - devc->mode = MD_4232; + devc->model = MD_4232; break; case 0xb2: devc->chip_name = "CS4232A"; - devc->mode = MD_4232; + devc->model = MD_4232; break; case 0x80: @@ -1358,15 +1376,28 @@ if (ad_read (devc, 23) != tmp) /* AD1845 ? */ { devc->chip_name = "AD1845"; - devc->mode = MD_1845; + devc->model = MD_1845; + } + else if (interwave) + { + devc->model = MD_IWAVE; + devc->chip_name = "IWave"; } ad_write (devc, 23, tmp); /* Restore */ } break; - default: /* Assume CS4231 */ - devc->mode = MD_4231; + default: /* Assume CS4231 or OPTi 82C930 */ + if (optiC930) + { + devc->chip_name = "82C930"; + devc->model = MD_C930; + } + else + { + devc->model = MD_4231; + } } } @@ -1379,11 +1410,32 @@ DDB (printk ("ad1848_detect() - step L\n")); if (ad_flags) { - if (devc->mode != MD_1848) + if (devc->model != MD_1848) *ad_flags |= AD_F_CS4231; } DDB (printk ("ad1848_detect() - Detected OK\n")); + + if (devc->model == MD_1848 && ad1847_flag) + devc->chip_name = "AD1847"; + + for (i = 0; i < 16; i++) + ad_write (devc, i, init_values[i]); + + ad_mute (devc); /* Initialize some variables */ + ad_unmute (devc); /* Leave it unmuted now */ + + if (devc->model > MD_1848) + { + ad_write (devc, 12, ad_read (devc, 12) | 0x40); /* Mode2 = enabled */ + + if (devc->model == MD_IWAVE) + ad_write (devc, 12, 0x6c); /* Select codec mode 3 */ + + for (i = 16; i < 32; i++) + ad_write (devc, i, init_values[i]); + } + return 1; } @@ -1396,24 +1448,14 @@ * The actually used IRQ is ABS(irq). */ - /* - * Initial values for the indirect registers of CS4248/AD1848. - */ - static int init_values[] = - { - 0xa8, 0xa8, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, - 0x00, 0x0c, 0x02, 0x00, 0x8a, 0x01, 0x00, 0x00, - /* Positions 16 to 31 just for CS4231 */ - 0x80, 0x00, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - int i, my_dev; + int my_dev; + char dev_name[100]; ad1848_info *devc = &dev_info[nr_ad1848_devs]; - if (!ad1848_detect (io_base, NULL, osp)) - return; + int audio_flags = DMA_AUTOMODE; + request_region (devc->base, 4, devc->chip_name); @@ -1422,141 +1464,129 @@ devc->timer_ticks = 0; devc->osp = osp; - if (nr_ad1848_devs != 0) - { - memcpy ((char *) &ad1848_pcm_operations[nr_ad1848_devs], - (char *) &ad1848_pcm_operations[0], - sizeof (struct audio_operations)); - } - - for (i = 0; i < 16; i++) - ad_write (devc, i, init_values[i]); - - ad_mute (devc); /* Initialize some variables */ - ad_unmute (devc); /* Leave it unmuted now */ - - if (devc->mode > MD_1848) + if (devc->model > MD_1848) { if (dma_capture == dma_playback || dma_capture == -1 || dma_playback == -1) { ad_write (devc, 9, ad_read (devc, 9) | 0x04); /* Single DMA mode */ - ad1848_pcm_operations[nr_ad1848_devs].flags &= ~DMA_DUPLEX; + audio_flags &= ~DMA_DUPLEX; } else { ad_write (devc, 9, ad_read (devc, 9) & ~0x04); /* Dual DMA mode */ - ad1848_pcm_operations[nr_ad1848_devs].flags |= DMA_DUPLEX; + audio_flags |= DMA_DUPLEX; } - ad_write (devc, 12, ad_read (devc, 12) | 0x40); /* Mode2 = enabled */ - for (i = 16; i < 32; i++) - ad_write (devc, i, init_values[i]); - - - if (devc->mode == MD_1845) + if (devc->model == MD_1845) ad_write (devc, 27, ad_read (devc, 27) | 0x08); /* Alternate freq select enabled */ + + if (devc->model == MD_IWAVE) + { /* Some magic Interwave specific initialization */ + ad_write (devc, 12, 0x6c); /* Select codec mode 3 */ + ad_write (devc, 17, 0xc2); /* Alternate feature enable */ + } } else { - ad1848_pcm_operations[nr_ad1848_devs].flags &= ~DMA_DUPLEX; + audio_flags &= ~DMA_DUPLEX; ad_write (devc, 9, ad_read (devc, 9) | 0x04); /* Single DMA mode */ } outb (0, io_Status (devc)); /* Clear pending interrupts */ if (name != NULL && name[0] != 0) - sprintf (ad1848_pcm_operations[nr_ad1848_devs].name, + sprintf (dev_name, "%s (%s)", name, devc->chip_name); else - sprintf (ad1848_pcm_operations[nr_ad1848_devs].name, + sprintf (dev_name, "Generic audio codec (%s)", devc->chip_name); - conf_printf2 (ad1848_pcm_operations[nr_ad1848_devs].name, + conf_printf2 (dev_name, devc->base, devc->irq, dma_playback, dma_capture); - if (num_audiodevs < MAX_AUDIO_DEV) + if (devc->model == MD_1848) + audio_flags |= DMA_HARDSTOP; + + if ((my_dev = sound_install_audiodrv (AUDIO_DRIVER_VERSION, + dev_name, + &ad1848_audio_driver, + sizeof (struct audio_driver), + audio_flags, + ad_format_mask[devc->model], + devc, + dma_playback, + dma_capture)) < 0) + { + return; + } + + if (irq > 0) { - audio_devs[my_dev = num_audiodevs++] = &ad1848_pcm_operations[nr_ad1848_devs]; - if (irq > 0) + irq2dev[irq] = devc->dev_no = my_dev; + if (snd_set_irq_handler (devc->irq, ad1848_interrupt, + "SoundPort", + devc->osp) < 0) { - audio_devs[my_dev]->devc = devc; - irq2dev[irq] = devc->dev_no = my_dev; - if (snd_set_irq_handler (devc->irq, ad1848_interrupt, - audio_devs[my_dev]->name, - devc->osp) < 0) - { - printk ("ad1848: IRQ in use\n"); - } + printk ("ad1848: IRQ in use\n"); + } -#ifdef NO_IRQ_TEST - if (devc->mode != MD_1848) - { - int x; - unsigned char tmp = ad_read (devc, 16); + if (devc->model != MD_1848) + { + int x; + unsigned char tmp = ad_read (devc, 16); - devc->timer_ticks = 0; + devc->timer_ticks = 0; - ad_write (devc, 21, 0x00); /* Timer msb */ - ad_write (devc, 20, 0x10); /* Timer lsb */ + ad_write (devc, 21, 0x00); /* Timer MSB */ + ad_write (devc, 20, 0x10); /* Timer LSB */ - ad_write (devc, 16, tmp | 0x40); /* Enable timer */ - for (x = 0; x < 100000 && devc->timer_ticks == 0; x++); - ad_write (devc, 16, tmp & ~0x40); /* Disable timer */ - - if (devc->timer_ticks == 0) - printk ("[IRQ conflict???]"); - else - devc->irq_ok = 1; + ad_write (devc, 16, tmp | 0x40); /* Enable timer */ + for (x = 0; x < 100000 && devc->timer_ticks == 0; x++); + ad_write (devc, 16, tmp & ~0x40); /* Disable timer */ - } + if (devc->timer_ticks == 0) + printk ("ad1848: Interrupt test failed (IRQ%d)\n", devc->irq); else - devc->irq_ok = 1; /* Couldn't test. assume it's OK */ -#else - devc->irq_ok = 1; -#endif + devc->irq_ok = 1; } - else if (irq < 0) - irq2dev[-irq] = devc->dev_no = my_dev; - - audio_devs[my_dev]->dmachan1 = dma_playback; - audio_devs[my_dev]->dmachan2 = dma_capture; - audio_devs[my_dev]->buffsize = DSP_BUFFSIZE; - audio_devs[my_dev]->devc = devc; - audio_devs[my_dev]->format_mask = ad_format_mask[devc->mode]; - nr_ad1848_devs++; + else + devc->irq_ok = 1; /* Couldn't test. assume it's OK */ + } + else if (irq < 0) + irq2dev[-irq] = devc->dev_no = my_dev; + nr_ad1848_devs++; #ifdef CONFIG_SEQUENCER - if (devc->mode != MD_1848 && devc->mode != MD_1845 && devc->irq_ok) - ad1848_tmr_install (my_dev); + if (devc->model != MD_1848 && devc->model != MD_1845 && devc->irq_ok) + ad1848_tmr_install (my_dev); #endif - if (!share_dma) - { - if (sound_alloc_dma (dma_playback, "Sound System")) - printk ("ad1848.c: Can't allocate DMA%d\n", dma_playback); - - if (dma_capture != dma_playback) - if (sound_alloc_dma (dma_capture, "Sound System (capture)")) - printk ("ad1848.c: Can't allocate DMA%d\n", dma_capture); - } + if (!share_dma) + { + if (sound_alloc_dma (dma_playback, "Sound System")) + printk ("ad1848.c: Can't allocate DMA%d\n", dma_playback); - /* - * Toggle the MCE bit. It completes the initialization phase. - */ + if (dma_capture != dma_playback) + if (sound_alloc_dma (dma_capture, "Sound System (capture)")) + printk ("ad1848.c: Can't allocate DMA%d\n", dma_capture); + } - ad_enter_MCE (devc); /* In case the bit was off */ - ad_leave_MCE (devc); + /* + * Toggle the MCE bit. It completes the initialization phase. + */ - if (num_mixers < MAX_MIXER_DEV) - { - mixer2codec[num_mixers] = my_dev + 1; - audio_devs[my_dev]->mixer_dev = num_mixers; - mixer_devs[num_mixers++] = &ad1848_mixer_operations; - ad1848_mixer_reset (devc); - } + ad_enter_MCE (devc); /* In case the bit was off */ + ad_leave_MCE (devc); + ad1848_mixer_reset (devc); + + if (sound_install_mixer (MIXER_DRIVER_VERSION, + dev_name, + &ad1848_mixer_operations, + sizeof (struct mixer_operations), + devc) >= 0) + { + audio_devs[my_dev]->mixer_dev = num_mixers - 1; } - else - printk ("AD1848: Too many PCM devices available\n"); } void @@ -1633,21 +1663,21 @@ if (status & 0x01) { - if (devc->mode != MD_1848) + if (devc->model != MD_1848) alt_stat = ad_read (devc, 24); - if (devc->opened && devc->irq_mode & PCM_ENABLE_INPUT && alt_stat & 0x20) + if (devc->opened && devc->audio_mode & PCM_ENABLE_INPUT && alt_stat & 0x20) { DMAbuf_inputintr (dev); } - if (devc->opened && devc->irq_mode & PCM_ENABLE_OUTPUT && + if (devc->opened && devc->audio_mode & PCM_ENABLE_OUTPUT && alt_stat & 0x10) { DMAbuf_outputintr (dev, 1); } - if (devc->mode != MD_1848 && alt_stat & 0x40) /* Timer interrupt */ + if (devc->model != MD_1848 && alt_stat & 0x40) /* Timer interrupt */ { devc->timer_ticks++; #ifdef CONFIG_SEQUENCER @@ -1657,7 +1687,7 @@ } } - if (devc->mode != MD_1848) + if (devc->model != MD_1848) ad_write (devc, 24, ad_read (devc, 24) & ~alt_stat); /* Selective ack */ else outb (0, io_Status (devc)); /* Clear interrupt status */ @@ -1681,11 +1711,220 @@ if (!opl3_detect (base, hw_config->osp)) return; - opl3_init (0, base, hw_config->osp); + opl3_init (base, hw_config->osp); request_region (base, 4, "OPL3/OPL2"); #endif } +#ifdef DESKPROXL +/* + * Very experimental initialization sequence for the integrated sound system + * of Compaq Deskpro XL. Will be moved somewhere else in future. + */ + +static int +init_deskpro (struct address_info *hw_config) +{ + unsigned char tmp; + + if ((tmp = inb (0xc44)) == 0xff) + { + DDB (printk ("init_deskpro: Dead port 0xc44\n")); + return 0; + } + + outb (tmp | 0x04, 0xc44); /* Select bank 1 */ + if (inb (0xc44) != 0x04) + { + DDB (printk ("init_deskpro: Invalid bank1 signature in port 0xc44\n")); + return 0; + } + +/* + * OK. It looks like a Deskpro so let's proceed. + */ + +/* + * I/O port 0xc44 Audio configuration register. + * + * bits 0xc0: Audio revision bits + * 0x00 = Compaq Business Audio + * 0x40 = MS Sound System Compatible (reset default) + * 0x80 = Reserved + * 0xc0 = Reserved + * bit 0x20: No Wait State Enable + * 0x00 = Disabled (reset default, DMA mode) + * 0x20 = Enabled (programmed I/O mode) + * bit 0x10: MS Sound System Decode Enable + * 0x00 = Decoding disabled (reset default) + * 0x10 = Decoding enabled + * bit 0x08: FM Synthesis Decode Enable + * 0x00 = Decoding Disabled (reset default) + * 0x08 = Decoding enabled + * bit 0x04 Bank select + * 0x00 = Bank 0 + * 0x04 = Bank 1 + * bits 0x03 MSS Base address + * 0x00 = 0x530 (reset default) + * 0x01 = 0x604 + * 0x02 = 0xf40 + * 0x03 = 0xe80 + */ + +#ifdef DEBUGXL + /* Debug printing */ + printk ("Port 0xc44 (before): "); + outb (tmp & ~0x04, 0xc44); + printk ("%02x ", inb (0xc44)); + outb (tmp | 0x04, 0xc44); + printk ("%02x\n", inb (0xc44)); +#endif + + /* Set bank 1 of the register */ + tmp = 0x58; /* MSS Mode, MSS&FM decode enabled */ + + switch (hw_config->io_base) + { + case 0x530: + tmp |= 0x00; + break; + case 0x604: + tmp |= 0x01; + break; + case 0xf40: + tmp |= 0x02; + break; + case 0xe80: + tmp |= 0x03; + break; + default: + DDB (printk ("init_deskpro: Invalid MSS port %x\n", + hw_config->io_base)); + return 0; + } + outb (tmp & ~0x04, 0xc44); /* Write to bank=0 */ + +#ifdef DEBUGXL + /* Debug printing */ + printk ("Port 0xc44 (after): "); + outb (tmp & ~0x04, 0xc44); /* Select bank=0 */ + printk ("%02x ", inb (0xc44)); + outb (tmp | 0x04, 0xc44); /* Select bank=1 */ + printk ("%02x\n", inb (0xc44)); +#endif + +/* + * I/O port 0xc45 FM Address Decode/MSS ID Register. + * + * bank=0, bits 0xfe: FM synthesis Decode Compare bits 7:1 (default=0x88) + * bank=0, bit 0x01: SBIC Power Control Bit + * 0x00 = Powered up + * 0x01 = Powered down + * bank=1, bits 0xfc: MSS ID (default=0x40) + */ + +#ifdef DEBUGXL + /* Debug printing */ + printk ("Port 0xc45 (before): "); + outb (tmp & ~0x04, 0xc44); /* Select bank=0 */ + printk ("%02x ", inb (0xc45)); + outb (tmp | 0x04, 0xc44); /* Select bank=1 */ + printk ("%02x\n", inb (0xc45)); +#endif + + outb (tmp & ~0x04, 0xc44); /* Select bank=0 */ + outb (0x88, 0xc45); /* FM base 7:0 = 0x88 */ + outb (tmp | 0x04, 0xc44); /* Select bank=1 */ + outb (0x10, 0xc45); /* MSS ID = 0x10 (MSS port returns 0x04) */ + +#ifdef DEBUGXL + /* Debug printing */ + printk ("Port 0xc45 (after): "); + outb (tmp & ~0x04, 0xc44); /* Select bank=0 */ + printk ("%02x ", inb (0xc45)); + outb (tmp | 0x04, 0xc44); /* Select bank=1 */ + printk ("%02x\n", inb (0xc45)); +#endif + + +/* + * I/O port 0xc46 FM Address Decode/Address ASIC Revision Register. + * + * bank=0, bits 0xff: FM synthesis Decode Compare bits 15:8 (default=0x03) + * bank=1, bits 0xff: Audio addressing ASIC id + */ + +#ifdef DEBUGXL + /* Debug printing */ + printk ("Port 0xc46 (before): "); + outb (tmp & ~0x04, 0xc44); /* Select bank=0 */ + printk ("%02x ", inb (0xc46)); + outb (tmp | 0x04, 0xc44); /* Select bank=1 */ + printk ("%02x\n", inb (0xc46)); +#endif + + outb (tmp & ~0x04, 0xc44); /* Select bank=0 */ + outb (0x03, 0xc46); /* FM base 15:8 = 0x03 */ + outb (tmp | 0x04, 0xc44); /* Select bank=1 */ + outb (0x11, 0xc46); /* ASIC ID = 0x11 */ + +#ifdef DEBUGXL + /* Debug printing */ + printk ("Port 0xc46 (after): "); + outb (tmp & ~0x04, 0xc44); /* Select bank=0 */ + printk ("%02x ", inb (0xc46)); + outb (tmp | 0x04, 0xc44); /* Select bank=1 */ + printk ("%02x\n", inb (0xc46)); +#endif + +/* + * I/O port 0xc47 FM Address Decode Register. + * + * bank=0, bits 0xff: Decode enable selection for various FM address bits + * bank=1, bits 0xff: Reserved + */ + +#ifdef DEBUGXL + /* Debug printing */ + printk ("Port 0xc47 (before): "); + outb (tmp & ~0x04, 0xc44); /* Select bank=0 */ + printk ("%02x ", inb (0xc47)); + outb (tmp | 0x04, 0xc44); /* Select bank=1 */ + printk ("%02x\n", inb (0xc47)); +#endif + + outb (tmp & ~0x04, 0xc44); /* Select bank=0 */ + outb (0x7c, 0xc47); /* FM decode enable bits = 0x7c */ + outb (tmp | 0x04, 0xc44); /* Select bank=1 */ + outb (0x00, 0xc47); /* Reserved bank1 = 0x00 */ + +#ifdef DEBUGXL + /* Debug printing */ + printk ("Port 0xc47 (after): "); + outb (tmp & ~0x04, 0xc44); /* Select bank=0 */ + printk ("%02x ", inb (0xc47)); + outb (tmp | 0x04, 0xc44); /* Select bank=1 */ + printk ("%02x\n", inb (0xc47)); +#endif + +/* + * I/O port 0xc6f = Audio Disable Function Register + */ + +#ifdef DEBUGXL + printk ("Port 0xc6f (before) = %02x\n", inb (0xc6f)); +#endif + + outb (0x80, 0xc6f); + +#ifdef DEBUGXL + printk ("Port 0xc6f (after) = %02x\n", inb (0xc6f)); +#endif + + return 1; +} +#endif + int probe_ms_sound (struct address_info *hw_config) { @@ -1705,9 +1944,17 @@ return ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp); } +#ifdef DESKPROXL + if (hw_config->card_subtype == 2) /* Compaq Deskpro XL */ + { + if (!init_deskpro (hw_config)) + return 0; + } +#endif + /* * Check if the IO port returns valid signature. The original MS Sound - * system returns 0x04 while some cards (AudioTriX Pro for example) + * system returns 0x04 while some cards (AudioTrix Pro for example) * return 0x00 or 0x0f. */ @@ -1720,6 +1967,7 @@ return 0; return 1; } + DDB (printk ("MSS signature = %x\n", tmp & 0x3f)); if ((tmp & 0x3f) != 0x04 && (tmp & 0x3f) != 0x0f && (tmp & 0x3f) != 0x00) @@ -1766,14 +2014,15 @@ return ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp); } -long -attach_ms_sound (long mem_start, struct address_info *hw_config) +void +attach_ms_sound (struct address_info *hw_config) { static char interrupt_bits[12] = { -1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20 }; - char bits; + char bits, dma2_bit = 0; + int ad_flags = 0; static char dma_bits[4] = { @@ -1782,9 +2031,11 @@ int config_port = hw_config->io_base + 0; int version_port = hw_config->io_base + 3; + int dma = hw_config->dma; + int dma2 = hw_config->dma2; - if (!ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp)) - return mem_start; + if (!ad1848_detect (hw_config->io_base + 4, &ad_flags, hw_config->osp)) + return; if (hw_config->card_subtype == 1) /* Has no IRQ/DMA registers */ { @@ -1793,7 +2044,7 @@ hw_config->dma, hw_config->dma2, 0, hw_config->osp); request_region (hw_config->io_base, 4, "WSS config"); - return mem_start; + return; } /* @@ -1802,20 +2053,51 @@ bits = interrupt_bits[hw_config->irq]; if (bits == -1) - return mem_start; + return; outb (bits | 0x40, config_port); if ((inb (version_port) & 0x40) == 0) printk ("[IRQ Conflict?]"); - outb (bits | dma_bits[hw_config->dma], config_port); /* Write IRQ+DMA setup */ +/* + * Handle the capture DMA channel + */ + + if (ad_flags & AD_F_CS4231 && dma2 != -1 && dma2 != dma) + { + if (!((dma == 0 && dma2 == 1) || + (dma == 1 && dma2 == 0) || + (dma == 3 && dma2 == 0))) + { /* Unsupported combination. Try to swap channels */ + int tmp = dma; + + dma = dma2; + dma2 = tmp; + } + + if ((dma == 0 && dma2 == 1) || + (dma == 1 && dma2 == 0) || + (dma == 3 && dma2 == 0)) + { + dma2_bit = 0x04; /* Enable capture DMA */ + } + else + { + printk ("MSS: Invalid capture DMA\n"); + dma2 = dma; + } + } + else + dma2 = dma; - ad1848_init ("MS Sound System", hw_config->io_base + 4, + outb (bits | dma_bits[dma] | dma2_bit, config_port); /* Write IRQ+DMA setup */ + + ad1848_init ("MSS audio codec", hw_config->io_base + 4, hw_config->irq, - hw_config->dma, - hw_config->dma, 0, hw_config->osp); + dma, + dma2, 0, + hw_config->osp); request_region (hw_config->io_base, 4, "WSS config"); - return mem_start; } void @@ -1838,15 +2120,14 @@ return ad1848_detect (hw_config->io_base, NULL, hw_config->osp); } -long -attach_pnp_ad1848 (long mem_start, struct address_info *hw_config) +void +attach_pnp_ad1848 (struct address_info *hw_config) { ad1848_init (hw_config->name, hw_config->io_base, hw_config->irq, hw_config->dma, hw_config->dma2, 0, hw_config->osp); - return mem_start; } void @@ -1888,7 +2169,7 @@ * the timer divider. */ - if (devc->mode == MD_1845) + if (devc->model == MD_1845) xtal_nsecs = 10050; else if (ad_read (devc, 8) & 0x01) xtal_nsecs = 9920; diff -ur --new-file old/linux/drivers/sound/ad1848_mixer.h new/linux/drivers/sound/ad1848_mixer.h --- old/linux/drivers/sound/ad1848_mixer.h Sun Mar 24 21:49:40 1996 +++ new/linux/drivers/sound/ad1848_mixer.h Sun Jun 30 10:43:36 1996 @@ -5,27 +5,11 @@ */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ diff -ur --new-file old/linux/drivers/sound/adlib_card.c new/linux/drivers/sound/adlib_card.c --- old/linux/drivers/sound/adlib_card.c Sun Mar 24 21:49:51 1996 +++ new/linux/drivers/sound/adlib_card.c Sun Jun 30 10:43:48 1996 @@ -5,27 +5,11 @@ */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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 @@ -34,14 +18,12 @@ #if defined(CONFIG_YM3812) -long -attach_adlib_card (long mem_start, struct address_info *hw_config) +void +attach_adlib_card (struct address_info *hw_config) { - mem_start = opl3_init (mem_start, hw_config->io_base, hw_config->osp); + opl3_init (hw_config->io_base, hw_config->osp); request_region (hw_config->io_base, 4, "OPL3/OPL2"); - - return mem_start; } int diff -ur --new-file old/linux/drivers/sound/aedsp16.c new/linux/drivers/sound/aedsp16.c --- old/linux/drivers/sound/aedsp16.c Fri Apr 12 08:49:42 1996 +++ new/linux/drivers/sound/aedsp16.c Mon Jul 15 08:55:11 1996 @@ -70,7 +70,7 @@ The Audio Excel DSP 16 Sound Card emulates both SBPRO and MSS; the voxware sound driver can be configured for SBPRO and MSS cards - at the same time, but the aedsp16 can't be two cards!! + at the same time, but the AEDSP16 can't be two cards!! When we configure it, we have to choose the SBPRO or the MSS emulation for AEDSP16. We also can install a *REAL* card of the other type (see [1], not tested but I can't see any reason for it to fail). @@ -143,7 +143,7 @@ this way. Should be interesting eventually write down a new ioctl for the - aedsp16, to let the suser() change the irq/dma/mirq on the fly. + AEDSP16, to let the suser() change the irq/dma/mirq on the fly. The thing is not trivial. In the real world, there's no need to have such an ioctl because when we configure the kernel for compile, we can choose the config @@ -154,7 +154,7 @@ the code to do it. More integration with voxware, using voxware low level routines to - read-write dsp is not possible because you may want to have MSS + read-write DSP is not possible because you may want to have MSS support and in that case we can not rely on the functions included in sb_dsp.c to control 0x2yy I/O ports. I will continue to use my own I/O functions. @@ -177,12 +177,12 @@ Request the 2x0h region in any case if we are using this card. - NOTE: the "(sbpro)" string with which we are requesting the aedsp16 region - (see code) does not mean necessarily that we are emulating sbpro. - It mean that the region is the sbpro I/O ports region. We use this + NOTE: the "(SBPro)" string with which we are requesting the AEDSP16 region + (see code) does not mean necessarily that we are emulating SBPro. + It mean that the region is the SBPro I/O ports region. We use this region to access the control registers of the card, and if emulating - sbpro, I/O sbpro registers too. If we are emulating MSS, the sbpro - registers are not used, in no way, to emulate an sbpro: they are + SBPro, I/O SBPro registers too. If we are emulating MSS, the SBPro + registers are not used, in no way, to emulate an SBPro: they are used only for configuration purposes. Someone pointed out that should be possible use both the SBPRO and MSS @@ -191,7 +191,7 @@ modes work together, but, for some reason unknown to me, without success. I think all the soft-config only cards have an init sequence similar to - this. If you have a card that is not an aedsp16, you can try to start + this. If you have a card that is not an AEDSP16, you can try to start with this module changing it (mainly in the CMD? I think) to fit your needs. @@ -202,7 +202,7 @@ v0.2 (ALPHA) - Cleanups. - Integrated with Linux voxware v 2.90-2 kernel sound driver. - - SoundBlaster Pro mode configuration. + - Sound Blaster Pro mode configuration. - Microsoft Sound System mode configuration. - MPU-401 mode configuration. v0.3 (ALPHA) @@ -216,7 +216,7 @@ - Added the code to request_region at device init (should go in the main body of voxware). v0.4 (BETA) - - Better configure.c patch for aedsp16 configuration (better + - Better configure.c patch for AEDSP16 configuration (better logic of inclusion of AEDSP16 support) - Modified the conditional compilation to better support more than one sound card of the emulated type (read the NOTES above) @@ -225,7 +225,7 @@ - Rearrangements and cleanups - Wiped out some unnecessary code and variables: this is kernel code so it is better save some TEXT and DATA - - Fixed the request_region code. We must allocate the aedsp16 (sbpro) + - Fixed the request_region code. We must allocate the AEDSP16 (SBPro) I/O ports in any case because they are used to access the DSP configuration registers and we can not allow anyone to get them. v0.5 @@ -349,7 +349,7 @@ }; /* - * Buffers to store audio card informations + * Buffers to store audio card information */ static char AudioExcelName[CARDNAMELEN + 1]; static char AudioExcelVersion[CARDVERLEN + 1]; @@ -431,7 +431,7 @@ } while (loop--); - printk ("[aedsp16] DSP Command (0x%x) timeout.\n", cmd); + printk ("[AEDSP16] DSP Command (0x%x) timeout.\n", cmd); return -1; } @@ -443,7 +443,7 @@ if (WriteDSPCommand (port, CMD6)) { - printk ("[aedsp16] CMD 0x%x: failed!\n", CMD6); + printk ("[AEDSP16] CMD 0x%x: failed!\n", CMD6); return -1; } @@ -461,7 +461,7 @@ { if (WriteDSPCommand (portbase, CMD3)) { - printk ("[aedsp16] CMD 0x%x: failed!\n", CMD3); + printk ("[AEDSP16] CMD 0x%x: failed!\n", CMD3); return -1; } @@ -473,32 +473,32 @@ #if defined(THIS_SHOULD_GO_AWAY) if (CheckDSPOkay (port)) { - printk ("[aedsp16] CheckDSPOkay: failed\n"); + printk ("[AEDSP16] CheckDSPOkay: failed\n"); return -1; } #else if (ReadData (port) == -1) { - printk ("[aedsp16] ReadData after CMD 0x%x: failed\n", CMD3); + printk ("[AEDSP16] ReadData after CMD 0x%x: failed\n", CMD3); return -1; } #endif if (WriteDSPCommand (portbase, CMD4)) { - printk ("[aedsp16] CMD 0x%x: failed!\n", CMD4); + printk ("[AEDSP16] CMD 0x%x: failed!\n", CMD4); return -1; } if (WriteDSPCommand (portbase, CMD5)) { - printk ("[aedsp16] CMD 0x%x: failed!\n", CMD5); + printk ("[AEDSP16] CMD 0x%x: failed!\n", CMD5); return -1; } if (WriteDSPCommand (portbase, oredparams)) { - printk ("[aedsp16] Initialization of (M)IRQ and DMA: failed!\n"); + printk ("[AEDSP16] Initialization of (M)IRQ and DMA: failed!\n"); return -1; } return 0; @@ -577,27 +577,27 @@ if (ResetBoard (portbase)) { - printk ("[aedsp16] ResetBoard: failed!\n"); + printk ("[AEDSP16] ResetBoard: failed!\n"); return -1; } #if defined(THIS_SHOULD_GO_AWAY) if (CheckDSPOkay (portbase)) { - printk ("[aedsp16] CheckDSPOkay: failed!\n"); + printk ("[AEDSP16] CheckDSPOkay: failed!\n"); return -1; } #endif if (WriteDSPCommand (portbase, CMD1)) { - printk ("[aedsp16] CMD 0x%x: failed!\n", CMD1); + printk ("[AEDSP16] CMD 0x%x: failed!\n", CMD1); return -1; } if (GetCardName (portbase)) { - printk ("[aedsp16] GetCardName: failed!\n"); + printk ("[AEDSP16] GetCardName: failed!\n"); return -1; } @@ -606,23 +606,23 @@ * if we have something different, we have to be warned. */ if (strcmp ("SC-6000", AudioExcelName)) - printk ("[aedsp16] Warning: non SC-6000 audio card!\n"); + printk ("[AEDSP16] Warning: non SC-6000 audio card!\n"); if (WriteDSPCommand (portbase, CMD2)) { - printk ("[aedsp16] CMD 0x%x: failed!\n", CMD2); + printk ("[AEDSP16] CMD 0x%x: failed!\n", CMD2); return -1; } if (GetCardVersion (portbase)) { - printk ("[aedsp16] GetCardVersion: failed!\n"); + printk ("[AEDSP16] GetCardVersion: failed!\n"); return -1; } if (SetUpBoard (portbase)) { - printk ("[aedsp16] SetUpBoard: failed!\n"); + printk ("[AEDSP16] SetUpBoard: failed!\n"); return -1; } @@ -630,7 +630,7 @@ { if (InitMSS (portbase)) { - printk ("[aedsp16] Can't initialize Microsoft Sound System mode.\n"); + printk ("[AEDSP16] Can't initialize Microsoft Sound System mode.\n"); return -1; } } @@ -706,7 +706,7 @@ * can allow me to release the requested region. */ if (!(ae_init & INIT_MPU401)) - request_region (hw_config->io_base, 0x0f, "aedsp16 (sbpro)"); + request_region (hw_config->io_base, 0x0f, "AEDSP16 (SBPro)"); #endif ae_init |= INIT_SBPRO; @@ -774,11 +774,11 @@ * can allow me to release the requested region. So when unloading * and then reloading it, we are going to have some nice Oops! */ - request_region (hw_config->io_base, 0x08, "aedsp16 (mss)"); + request_region (hw_config->io_base, 0x08, "AEDSP16 (MSS)"); #endif if (!(ae_init & INIT_MPU401)) - request_region (AEDSP16_BASE, 0x0f, "aedsp16 (sbpro)"); + request_region (AEDSP16_BASE, 0x0f, "AEDSP16 (SBPro)"); ae_init |= INIT_MSS; return 0; @@ -820,8 +820,8 @@ /* * If mpu401, the irq and dma are not important, do not touch it - * because we may use the default if sbpro is not yet configured, - * we may use the sbpro ones if configured, and nothing wrong + * because we may use the default if SBPro is not yet configured, + * we may use the SBPro ones if configured, and nothing wrong * should happen. * * The mirq default is 0, but once set it to non-0 value, we should @@ -837,11 +837,11 @@ * request any region because there is not a uninit routine that * can allow me to release the requested region. */ - request_region (hw_config->io_base, 0x02, "aedsp16 (mpu401)"); + request_region (hw_config->io_base, 0x02, "AEDSP16 (mpu401)"); #endif if (!(ae_init & (INIT_MSS | INIT_SBPRO))) - request_region (AEDSP16_BASE, 0x0f, "aedsp16 (sbpro)"); + request_region (AEDSP16_BASE, 0x0f, "AEDSP16 (SBPro)"); ae_init |= INIT_MPU401; return 0; @@ -859,7 +859,7 @@ ResetAEDSP16 (void) { #if defined(AEDSP16_DEBUG) - printk ("[aedsp16] ResetAEDSP16 called.\n"); + printk ("[AEDSP16] ResetAEDSP16 called.\n"); #endif return InitAEDSP16 (RESET_DSP16); } diff -ur --new-file old/linux/drivers/sound/audio.c new/linux/drivers/sound/audio.c --- old/linux/drivers/sound/audio.c Mon Mar 25 08:25:26 1996 +++ new/linux/drivers/sound/audio.c Sun Aug 18 09:46:48 1996 @@ -5,27 +5,11 @@ */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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 @@ -41,7 +25,7 @@ #define OFF 0 static int audio_mode[MAX_AUDIO_DEV]; -static int dev_nblock[MAX_AUDIO_DEV]; /* 1 if in noblocking mode */ +static int dev_nblock[MAX_AUDIO_DEV]; /* 1 if in nonblocking mode */ #define AM_NONE 0 #define AM_WRITE 1 @@ -108,8 +92,9 @@ if (DMAbuf_ioctl (dev, SNDCTL_DSP_SETFMT, (caddr_t) bits, 1) != bits) { + printk ("audio: Can't set number of bits on device %d\n", dev); audio_release (dev, file); - return -ENXIO; + return -(ENXIO); } if (dev_type == SND_DEV_AUDIO) @@ -143,7 +128,7 @@ p = dmap->qtail; - for (i = dmap->qlen; i < dmap->nbufs; i++) + for (i = dmap->qlen + 1; i < dmap->nbufs; i++) { memset (dmap->raw_buf + p * dmap->fragment_size, dmap->neutral_byte, @@ -240,7 +225,7 @@ dev_nblock[dev])) < 0) { /* Handle nonblocking mode */ - if (dev_nblock[dev] && buf_no == -EAGAIN) + if (dev_nblock[dev] && buf_no == -(EAGAIN)) return p; /* No more space. Return # of accepted bytes */ return buf_no; } @@ -251,15 +236,15 @@ if (l > (buf_size - buf_ptr)) l = (buf_size - buf_ptr); - if (!audio_devs[dev]->copy_from_user) + if (!audio_devs[dev]->d->copy_from_user) { /* * No device specific copy routine */ - memcpy_fromfs (&dma_buf[buf_ptr], &((buf)[p]), l); + memcpy_fromfs (&dma_buf[buf_ptr], &(buf)[p], l); } else - audio_devs[dev]->copy_from_user (dev, - dma_buf, buf_ptr, buf, p, l); + audio_devs[dev]->d->copy_from_user (dev, + dma_buf, buf_ptr, buf, p, l); if (local_conversion[dev] == AFMT_MU_LAW) { @@ -318,7 +303,7 @@ { /* Nonblocking mode handling. Return current # of bytes */ - if (dev_nblock[dev] && buf_no == -EAGAIN) + if (dev_nblock[dev] && buf_no == -(EAGAIN)) return p; return buf_no; @@ -341,7 +326,7 @@ translate_bytes (dsp_ulaw, (unsigned char *) dmabuf, l); } - memcpy_tofs (&((buf)[p]), dmabuf, l); + memcpy_tofs (&(buf)[p], dmabuf, l); DMAbuf_rmchars (dev, buf_no, l); @@ -366,17 +351,22 @@ else printk ("/dev/dsp%d: No coprocessor for this device\n", dev); - return -ENXIO; + return -(ENXIO); } else switch (cmd) { case SNDCTL_DSP_SYNC: + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return 0; + sync_output (dev); return DMAbuf_ioctl (dev, cmd, arg, 0); break; case SNDCTL_DSP_POST: + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return 0; sync_output (dev); return 0; break; @@ -391,11 +381,13 @@ break; case SNDCTL_DSP_SETFMT: - return snd_ioctl_return ((int *) arg, set_format (dev, get_fs_long ((long *) arg))); + return snd_ioctl_return ((int *) arg, set_format (dev, get_user ((int *) arg))); case SNDCTL_DSP_GETISPACE: + if (!(audio_devs[dev]->open_mode & OPEN_READ)) + return 0; if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX)) - return -EBUSY; + return -(EBUSY); { audio_buf_info info; @@ -405,13 +397,15 @@ if (err < 0) return err; - memcpy_tofs ((&((char *) arg)[0]), (char *) &info, sizeof (info)); + memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info)); return 0; } case SNDCTL_DSP_GETOSPACE: + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return 0; if ((audio_mode[dev] & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX)) - return -EBUSY; + return -(EBUSY); { audio_buf_info info; @@ -426,7 +420,7 @@ if (DMAbuf_get_curr_buffer (dev, &buf_no, &dma_buf, &buf_ptr, &buf_size) >= 0) info.bytes += buf_size - buf_ptr; - memcpy_tofs ((&((char *) arg)[0]), (char *) &info, sizeof (info)); + memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info)); return 0; } @@ -445,15 +439,15 @@ if (audio_devs[dev]->coproc) info |= DSP_CAP_COPROC; - if (audio_devs[dev]->local_qlen) /* Device has hidden buffers */ + if (audio_devs[dev]->d->local_qlen) /* Device has hidden buffers */ info |= DSP_CAP_BATCH; - if (audio_devs[dev]->trigger) /* Supports SETTRIGGER */ + if (audio_devs[dev]->d->trigger) /* Supports SETTRIGGER */ info |= DSP_CAP_TRIGGER; info |= DSP_CAP_MMAP; - memcpy_tofs ((&((char *) arg)[0]), (char *) &info, sizeof (info)); + memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info)); return 0; } break; @@ -463,13 +457,12 @@ } } -long -audio_init (long mem_start) +void +audio_init (void) { /* * NOTE! This routine could be called several times during boot. */ - return mem_start; } int diff -ur --new-file old/linux/drivers/sound/configure.c new/linux/drivers/sound/configure.c --- old/linux/drivers/sound/configure.c Fri Apr 12 08:49:42 1996 +++ new/linux/drivers/sound/configure.c Sat Jul 20 07:56:20 1996 @@ -8,27 +8,11 @@ * sound/configure.c - Configuration program for the Linux Sound Driver */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ @@ -83,14 +67,17 @@ #define AUDIO_CARDS (B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_GUS) | \ B (OPT_MSS) | B (OPT_GUS16) | B (OPT_GUSMAX) | B (OPT_TRIX) | \ B (OPT_SSCAPE)| B(OPT_MAD16) | B(OPT_CS4232)) -#define MIDI_CARDS (B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_MPU401) | \ +#define MPU_DEVS (B(OPT_PSS)|\ + B(OPT_CS4232)|B(OPT_SPNP)|B(OPT_MAUI)|B(OPT_SSCAPE)) +#define UART401_DEVS (SBDSP_DEVS|B(OPT_TRIX)|B(OPT_MAD16)) +#define MIDI_CARDS (MPU_DEVS | UART401_DEVS | \ + B (OPT_PSS) | B (OPT_SB) | B (OPT_PAS) | B (OPT_MPU401) | \ B (OPT_GUS) | B (OPT_TRIX) | B (OPT_SSCAPE)|B(OPT_MAD16) | \ B (OPT_CS4232)|B(OPT_MAUI)) -#define MPU_DEVS (B(OPT_PSS)|B(OPT_SSCAPE)|B(OPT_TRIX)|B(OPT_MAD16)|\ - B(OPT_CS4232)|B(OPT_SPNP)|B(OPT_MAUI)) #define AD1848_DEVS (B(OPT_GUS16)|B(OPT_MSS)|B(OPT_PSS)|B(OPT_GUSMAX)|\ B(OPT_SSCAPE)|B(OPT_TRIX)|B(OPT_MAD16)|B(OPT_CS4232)|\ B(OPT_SPNP)) +#define SBDSP_DEVS (B(OPT_SB)|B(OPT_SPNP)|B(OPT_MAD16)|B(OPT_TRIX)) #define SEQUENCER_DEVS (OPT_MIDI|OPT_YM3812|OPT_ADLIB|OPT_GUS|OPT_MAUI|MIDI_CARDS) /* * Options that have been disabled for some reason (incompletely implemented @@ -161,7 +148,7 @@ char *questions[] = { "ProAudioSpectrum 16 support", - "SoundBlaster (SB, SBPro, SB16, clones) support", + "Sound Blaster (SB, SBPro, SB16, clones) support", "Generic OPL2/OPL3 FM synthesizer support", "Gravis Ultrasound support", "MPU-401 support (NOT for SB16)", @@ -170,8 +157,8 @@ "16 bit sampling option of GUS (_NOT_ GUS MAX)", "GUS MAX support", "Microsoft Sound System support", - "Ensoniq Soundscape support", - "MediaTriX AudioTriX Pro support", + "Ensoniq SoundScape support", + "MediaTrix AudioTrix Pro support", "Support for MAD16 and/or Mozart based cards", "Support for Crystal CS4232 based (PnP) cards", "Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers", @@ -196,10 +183,10 @@ "you have some other card made by MediaVision or Logitech as\n" "they are not PAS16 compatible.\n", - "Enable this if you have an original SoundBlaster card made by\n" + "Enable this if you have an original Sound Blaster card made by\n" "Creative Labs or a 100%% hardware compatible clone. For an\n" "unknown card you may want to try this if it claims to be\n" - "SoundBlaster compatible.\n", + "Sound Blaster compatible.\n", "Enable this option if your sound card has a Yamaha OPL2 or OPL3\n" "FM synthesizer chip.\n", @@ -232,10 +219,10 @@ "card made by Microsoft or the Aztech SG 16 Pro or NX16 Pro.\n", "Enable this if you have a sound card based on the Ensoniq\n" - "Soundscape chipset. Such cards are being manufactured by Ensoniq,\n" + "SoundScape chipset. Such cards are being manufactured by Ensoniq,\n" "Spea and Reveal (Reveal makes other cards as well).\n", - "Enable this option if you have the AudioTriX Pro sound card\n" + "Enable this option if you have the AudioTrix Pro sound card\n" "manufactured by MediaTrix.\n", "Enable this if your card has a Mozart (OAK OTI-601) or MAD16 (OPTi\n" @@ -253,10 +240,10 @@ "Use this option to enable experimental support for cards that\n" "use the Plug and Play protocol.\n", - "Enable this option if your card is a SoundBlaster Pro or\n" - "SoundBlaster 16. It also works with many SoundBlaster Pro clones.\n", + "Enable this option if your card is a Sound Blaster Pro or\n" + "Sound Blaster 16. It also works with many Sound Blaster Pro clones.\n", - "Enable this if you have a SoundBlaster 16, including the AWE32.\n", + "Enable this if you have a Sound Blaster 16, including the AWE32.\n", "Enable this if you have an Audio Excel DSP16 card. See the file\n" "Readme.aedsp16 for more information.\n", @@ -294,6 +281,14 @@ } , { + "SBDSP", SBDSP_DEVS + } + , + { + "UART401", UART401_DEVS + } + , + { "SEQUENCER", SEQUENCER_DEVS } , @@ -687,11 +682,14 @@ printf ("#define SELECTED_SOUND_OPTIONS\t0x%08x\n", selected_options); fprintf (stderr, "Old configuration copied.\n"); +#if defined(linux) || defined(Solaris) build_defines (); +#endif old_config_used = 1; return 1; } +#if defined(linux) || defined(Solaris) void build_defines (void) { @@ -725,6 +723,7 @@ fprintf (optf, "\n"); fclose (optf); } +#endif void ask_parameters (void) @@ -749,22 +748,22 @@ "Check from manual of the card"); ask_int_choice (B (OPT_SB), "SBC_IRQ", - "SoundBlaster IRQ", + "Sound Blaster IRQ", FMT_INT, 7, "Check from manual of the card"); ask_int_choice (B (OPT_SB), "SBC_DMA", - "SoundBlaster DMA", + "Sound Blaster DMA", FMT_INT, 1, "0, 1 or 3"); ask_int_choice (B (OPT_SB), "SB_DMA2", - "SoundBlaster 16 bit DMA (_REQUIRED_for SB16, Jazz16, SMW)", + "Sound Blaster 16 bit DMA (_REQUIRED_for SB16, Jazz16, SMW)", FMT_INT, 5, - "5, 6 or 7"); + "5, 6 or 7 (use 1 for 8 bit cards)"); ask_int_choice (B (OPT_SB), "SB_MPU_BASE", "MPU401 I/O base of SB16, Jazz16 and ES1688", @@ -776,7 +775,7 @@ "SB MPU401 IRQ (Jazz16, SM Wave and ES1688)", FMT_INT, -1, - "Check from manual of the card"); + "Use -1 with SB16"); ask_int_choice (B (OPT_PAS), "PAS_IRQ", "PAS16 IRQ", @@ -945,40 +944,35 @@ "0, 1 or 3"); ask_int_choice (B (OPT_SSCAPE), "SSCAPE_BASE", - "Soundscape MIDI I/O base", + "SoundScape MIDI I/O base", FMT_HEX, 0x330, - ""); + "320, 330, 340 or 350"); ask_int_choice (B (OPT_SSCAPE), "SSCAPE_IRQ", - "Soundscape MIDI IRQ", + "SoundScape MIDI IRQ", FMT_INT, 9, ""); ask_int_choice (B (OPT_SSCAPE), "SSCAPE_DMA", - "Soundscape initialization DMA", + "SoundScape initialization DMA", FMT_INT, 3, "0, 1 or 3"); ask_int_choice (B (OPT_SSCAPE), "SSCAPE_MSS_BASE", - "Soundscape audio I/O base", + "SoundScape audio I/O base", FMT_HEX, 0x534, "534, 608, E84 or F44"); ask_int_choice (B (OPT_SSCAPE), "SSCAPE_MSS_IRQ", - "Soundscape audio IRQ", + "SoundScape audio IRQ", FMT_INT, 11, "7, 9, 10 or 11"); - ask_int_choice (B (OPT_SSCAPE), "SSCAPE_MSS_DMA", - "Soundscape audio DMA", - FMT_INT, - 0, - "0, 1 or 3"); if (selected_options & B (OPT_SSCAPE)) { @@ -995,55 +989,55 @@ } ask_int_choice (B (OPT_TRIX), "TRIX_BASE", - "AudioTriX audio I/O base", + "AudioTrix audio I/O base", FMT_HEX, 0x530, "530, 604, E80 or F40"); ask_int_choice (B (OPT_TRIX), "TRIX_IRQ", - "AudioTriX audio IRQ", + "AudioTrix audio IRQ", FMT_INT, 11, "7, 9, 10 or 11"); ask_int_choice (B (OPT_TRIX), "TRIX_DMA", - "AudioTriX audio DMA", + "AudioTrix audio DMA", FMT_INT, 0, "0, 1 or 3"); ask_int_choice (B (OPT_TRIX), "TRIX_DMA2", - "AudioTriX second (duplex) DMA", + "AudioTrix second (duplex) DMA", FMT_INT, 3, "0, 1 or 3"); ask_int_choice (B (OPT_TRIX), "TRIX_MPU_BASE", - "AudioTriX MIDI I/O base", + "AudioTrix MIDI I/O base", FMT_HEX, 0x330, "330, 370, 3B0 or 3F0"); ask_int_choice (B (OPT_TRIX), "TRIX_MPU_IRQ", - "AudioTriX MIDI IRQ", + "AudioTrix MIDI IRQ", FMT_INT, 9, "3, 4, 5, 7 or 9"); ask_int_choice (B (OPT_TRIX), "TRIX_SB_BASE", - "AudioTriX SB I/O base", + "AudioTrix SB I/O base", FMT_HEX, 0x220, "220, 210, 230, 240, 250, 260 or 270"); ask_int_choice (B (OPT_TRIX), "TRIX_SB_IRQ", - "AudioTriX SB IRQ", + "AudioTrix SB IRQ", FMT_INT, 7, "3, 4, 5 or 7"); ask_int_choice (B (OPT_TRIX), "TRIX_SB_DMA", - "AudioTriX SB DMA", + "AudioTrix SB DMA", FMT_INT, 1, "1 or 3"); @@ -1141,7 +1135,6 @@ /* * Some "hardcoded" options */ - printf ("bool 'Support for SM Wave' CONFIG_SMWAVE\n"); dump_only = 1; selected_options = 0; @@ -1372,10 +1365,10 @@ { if (think_positively ( - "Do you want support for the Audio Excel SoundBlaster Pro mode", + "Do you want support for the Audio Excel Sound Blaster Pro mode", 1, "Enable this option if you want the Audio Excel sound card to operate\n" - "in SoundBlaster Pro mode.\n")) + "in Sound Blaster Pro mode.\n")) { printf ("#define AEDSP16_SBPRO\n"); sel1 = 1; @@ -1410,7 +1403,7 @@ { genld_again: if (think_positively ("Do you wish to include an LD file", 1, - "If you want to emulate the SoundBlaster card and you have a DSPxxx.LD\n" + "If you want to emulate the Sound Blaster card and you have a DSPxxx.LD\n" "file then you must include the LD in the kernel.\n")) { char path[512]; @@ -1450,10 +1443,10 @@ if (think_positively ("Do you want to include TRXPRO.HEX in your kernel", 1, - "The MediaTriX AudioTrix Pro has an onboard microcontroller which\n" + "The MediaTrix AudioTrix Pro has an on-board microcontroller which\n" "needs to be initialized by downloading the code from the file TRXPRO.HEX\n" "in the DOS driver directory. If you don't have the TRXPRO.HEX file handy\n" - "you may skip this step. However, the SB and MPU-401 modes of AudioTriX\n" + "you may skip this step. However, the SB and MPU-401 modes of AudioTrix\n" "Pro will not work without this file!\n")) { char path[512]; @@ -1467,6 +1460,15 @@ goto hex2hex_again; printf ("/*build hex2hex %s trix_boot.h trix_boot */\n", path); printf ("#define INCLUDE_TRIX_BOOT\n"); + } + } + + if (selected_options & B (OPT_MSS)) + { + if (think_positively ("Support for builtin sound of Compaq Deskpro XL", 0, + "Enable this if you have Compaq Deskpro XL.\n")) + { + printf ("#define DESKPROXL\n"); } } diff -ur --new-file old/linux/drivers/sound/cs4232.c new/linux/drivers/sound/cs4232.c --- old/linux/drivers/sound/cs4232.c Fri Apr 12 08:49:42 1996 +++ new/linux/drivers/sound/cs4232.c Sat Jul 6 10:31:42 1996 @@ -9,27 +9,11 @@ * supported. Other interfaces are left uninitialized. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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 @@ -67,10 +51,9 @@ return 0; } -long -attach_cs4232_mpu (long mem_start, struct address_info *hw_config) +void +attach_cs4232_mpu (struct address_info *hw_config) { - return mem_start; } static unsigned char crystal_key[] = /* A 32 byte magic key sequence */ @@ -122,7 +105,7 @@ for (n = 0; n < 4; n++) { - cs_sleep_flag.mode = WK_NONE; + cs_sleep_flag.flags = WK_NONE; /* * Wake up the card by sending a 32 byte Crystal key to the key port. */ @@ -131,20 +114,20 @@ { - unsigned long tl; + unsigned long tlimit; if (HZ / 10) - current_set_timeout (tl = jiffies + (HZ / 10)); + current_set_timeout (tlimit = jiffies + (HZ / 10)); else - tl = (unsigned long) -1; - cs_sleep_flag.mode = WK_SLEEP; + tlimit = (unsigned long) -1; + cs_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&cs_sleeper); - if (!(cs_sleep_flag.mode & WK_WAKEUP)) + if (!(cs_sleep_flag.flags & WK_WAKEUP)) { - if (jiffies >= tl) - cs_sleep_flag.mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + cs_sleep_flag.flags |= WK_TIMEOUT; } - cs_sleep_flag.mode &= ~WK_SLEEP; + cs_sleep_flag.flags &= ~WK_SLEEP; }; /* Delay */ /* @@ -159,14 +142,14 @@ */ CS_OUT2 (0x15, 0x00); /* Select logical device 0 (WSS/SB/FM) */ - CS_OUT3 (0x47, (base >> 8) & 0xff, base & 0xff); /* WSSbase */ + CS_OUT3 (0x47, (base >> 8) & 0xff, base & 0xff); /* WSS base */ if (check_region (0x388, 4)) /* Not free */ - CS_OUT3 (0x48, 0x00, 0x00) /* FMbase off */ + CS_OUT3 (0x48, 0x00, 0x00) /* FM base off */ else - CS_OUT3 (0x48, 0x03, 0x88); /* FMbase 0x388 */ + CS_OUT3 (0x48, 0x03, 0x88); /* FM base 0x388 */ - CS_OUT3 (0x42, 0x00, 0x00); /* SBbase off */ + CS_OUT3 (0x42, 0x00, 0x00); /* SB base off */ CS_OUT2 (0x22, irq); /* SB+WSS IRQ */ CS_OUT2 (0x2a, dma1); /* SB+WSS DMA */ @@ -179,20 +162,20 @@ { - unsigned long tl; + unsigned long tlimit; if (HZ / 10) - current_set_timeout (tl = jiffies + (HZ / 10)); + current_set_timeout (tlimit = jiffies + (HZ / 10)); else - tl = (unsigned long) -1; - cs_sleep_flag.mode = WK_SLEEP; + tlimit = (unsigned long) -1; + cs_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&cs_sleeper); - if (!(cs_sleep_flag.mode & WK_WAKEUP)) + if (!(cs_sleep_flag.flags & WK_WAKEUP)) { - if (jiffies >= tl) - cs_sleep_flag.mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + cs_sleep_flag.flags |= WK_TIMEOUT; } - cs_sleep_flag.mode &= ~WK_SLEEP; + cs_sleep_flag.flags &= ~WK_SLEEP; }; /* Delay */ /* @@ -203,7 +186,7 @@ if (mpu_base != 0 && mpu_irq != 0) { CS_OUT2 (0x15, 0x03); /* Select logical device 3 (MPU) */ - CS_OUT3 (0x47, (mpu_base >> 8) & 0xff, mpu_base & 0xff); /* MPUbase */ + CS_OUT3 (0x47, (mpu_base >> 8) & 0xff, mpu_base & 0xff); /* MPU base */ CS_OUT2 (0x22, mpu_irq); /* MPU IRQ */ CS_OUT2 (0x33, 0x01); /* Activate logical dev 3 */ } @@ -216,20 +199,20 @@ { - unsigned long tl; + unsigned long tlimit; if (HZ / 5) - current_set_timeout (tl = jiffies + (HZ / 5)); + current_set_timeout (tlimit = jiffies + (HZ / 5)); else - tl = (unsigned long) -1; - cs_sleep_flag.mode = WK_SLEEP; + tlimit = (unsigned long) -1; + cs_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&cs_sleeper); - if (!(cs_sleep_flag.mode & WK_WAKEUP)) + if (!(cs_sleep_flag.flags & WK_WAKEUP)) { - if (jiffies >= tl) - cs_sleep_flag.mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + cs_sleep_flag.flags |= WK_TIMEOUT; } - cs_sleep_flag.mode &= ~WK_SLEEP; + cs_sleep_flag.flags &= ~WK_SLEEP; }; /* Delay */ /* @@ -241,28 +224,28 @@ { - unsigned long tl; + unsigned long tlimit; if (HZ) - current_set_timeout (tl = jiffies + (HZ)); + current_set_timeout (tlimit = jiffies + (HZ)); else - tl = (unsigned long) -1; - cs_sleep_flag.mode = WK_SLEEP; + tlimit = (unsigned long) -1; + cs_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&cs_sleeper); - if (!(cs_sleep_flag.mode & WK_WAKEUP)) + if (!(cs_sleep_flag.flags & WK_WAKEUP)) { - if (jiffies >= tl) - cs_sleep_flag.mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + cs_sleep_flag.flags |= WK_TIMEOUT; } - cs_sleep_flag.mode &= ~WK_SLEEP; + cs_sleep_flag.flags &= ~WK_SLEEP; }; /* Longer delay */ } return 0; } -long -attach_cs4232 (long mem_start, struct address_info *hw_config) +void +attach_cs4232 (struct address_info *hw_config) { int base = hw_config->io_base, irq = hw_config->irq; int dma1 = hw_config->dma, dma2 = hw_config->dma2; @@ -297,7 +280,7 @@ if (probe_mpu401 (&hw_config2)) { mpu_detected = 1; - mem_start = attach_mpu401 (mem_start, &hw_config2); + attach_mpu401 (&hw_config2); } else { @@ -305,7 +288,6 @@ } } #endif - return mem_start; } void diff -ur --new-file old/linux/drivers/sound/dev_table.c new/linux/drivers/sound/dev_table.c --- old/linux/drivers/sound/dev_table.c Sun Mar 24 21:49:56 1996 +++ new/linux/drivers/sound/dev_table.c Sun Jun 30 10:43:53 1996 @@ -4,27 +4,11 @@ * Device call tables. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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 @@ -48,36 +32,36 @@ return -1; } -static long -start_services (long mem_start) +static void +start_services (void) { int soundcards_installed; if (!(soundcards_installed = sndtable_get_cardcount ())) - return mem_start; /* No cards detected */ + return; /* No cards detected */ #ifdef CONFIG_AUDIO if (num_audiodevs) /* Audio devices present */ { - DMAbuf_init (0); - audio_init (0); + DMAbuf_init (); + audio_init (); } #endif #ifdef CONFIG_MIDI if (num_midis) - MIDIbuf_init (0); + MIDIbuf_init (); #endif #ifdef CONFIG_SEQUENCER if (num_midis + num_synths) - sequencer_init (0); + sequencer_init (); #endif - return mem_start; + return; } -static long -start_cards (long mem_start) +static void +start_cards (void) { int i, n = num_sound_cards; int drv; @@ -112,7 +96,7 @@ if (sound_drivers[drv].probe (&snd_installed_cards[i].config)) { - mem_start = sound_drivers[drv].attach (mem_start, &snd_installed_cards[i].config); + sound_drivers[drv].attach (&snd_installed_cards[i].config); } else @@ -123,13 +107,12 @@ if (trace_init) printk ("Sound initialization complete\n"); - return mem_start; } -long -sndtable_init (long mem_start) +void +sndtable_init (void) { - return start_cards (mem_start); + return start_cards (); } void @@ -173,6 +156,7 @@ { if ((drv = snd_find_driver (type)) != -1) { + DDB (printk (" card %d", i)); if (sound_drivers[drv].unload) { sound_drivers[drv].unload (&snd_installed_cards[i].config); @@ -181,19 +165,19 @@ } } } + DDB (printk ("\n")); save_flags (flags); cli (); restore_flags (flags); - } int sndtable_probe (int unit, struct address_info *hw_config) { - int i, sel = -1, n = num_sound_cards; + int sel = -1; DDB (printk ("sndtable_probe(%d)\n", unit)); @@ -202,10 +186,6 @@ sound_started = 1; - for (i = 0; i < n && sel == -1 && snd_installed_cards[i].card_type; i++) - if (snd_installed_cards[i].enabled) - if (snd_installed_cards[i].card_type == unit) - sel = i; if (sel == -1 && num_sound_cards < max_sound_cards) { @@ -247,8 +227,76 @@ if (sound_drivers[drv].probe (hw_config)) { + DDB (printk ("Hardware probed OK\n")); return TRUE; + } + + DDB (printk ("Failed to find hardware\n")); + snd_installed_cards[sel].enabled = 0; /* + * Mark as not detected + */ + return FALSE; + } + + return FALSE; +} + +int +sndtable_start_card (int unit, struct address_info *hw_config) +{ + int sel = -1; + + DDB (printk ("sndtable_probe(%d)\n", unit)); + + if (!unit) + return TRUE; + + sound_started = 1; + + if (sel == -1 && num_sound_cards < max_sound_cards) + { + int i; + + i = sel = (num_sound_cards++); + + snd_installed_cards[sel].card_type = unit; + snd_installed_cards[sel].enabled = 1; + } + + if (sel != -1) + { + int drv; + + snd_installed_cards[sel].for_driver_use = NULL; + snd_installed_cards[sel].config.io_base = hw_config->io_base; + snd_installed_cards[sel].config.irq = hw_config->irq; + snd_installed_cards[sel].config.dma = hw_config->dma; + snd_installed_cards[sel].config.dma2 = hw_config->dma2; + snd_installed_cards[sel].config.name = hw_config->name; + snd_installed_cards[sel].config.always_detect = hw_config->always_detect; + snd_installed_cards[sel].config.driver_use_1 = hw_config->driver_use_1; + snd_installed_cards[sel].config.driver_use_2 = hw_config->driver_use_2; + snd_installed_cards[sel].config.card_subtype = hw_config->card_subtype; + snd_installed_cards[sel].config.osp = hw_config->osp; + + if ((drv = snd_find_driver (snd_installed_cards[sel].card_type)) == -1) + { + snd_installed_cards[sel].enabled = 0; + DDB (printk ("Failed to find driver\n")); + return FALSE; + } + DDB (printk ("Driver name '%s'\n", sound_drivers[drv].name)); + + hw_config->card_subtype = + snd_installed_cards[sel].config.card_subtype = + sound_drivers[drv].card_subtype; + + if (sound_drivers[drv].probe (hw_config)) + { DDB (printk ("Hardware probed OK\n")); + sound_drivers[drv].attach (hw_config); + start_services (); + return TRUE; } DDB (printk ("Failed to find hardware\n")); @@ -270,8 +318,7 @@ if (!unit) { - if (sndtable_init (0) != 0) - panic ("sound: Invalid memory allocation\n"); + sndtable_init (); return TRUE; } @@ -299,12 +346,11 @@ { DDB (printk ("Located card - calling attach routine\n")); - if (sound_drivers[drv].attach (0, hw_config) != 0) - panic ("sound: Invalid memory allocation\n"); + sound_drivers[drv].attach (hw_config); DDB (printk ("attach routine finished\n")); } - start_services (0); + start_services (); return TRUE; } @@ -361,7 +407,7 @@ for (i = 1; i <= ints[0]; i++) { - int card_type, ioaddr, irq, dma, ptr, j; + int card_type, ioaddr, irq, dma, dma2, ptr, j; unsigned int val; val = (unsigned int) ints[i]; @@ -379,6 +425,7 @@ ioaddr = (val & 0x000fff00) >> 8; irq = (val & 0x000000f0) >> 4; dma = (val & 0x0000000f); + dma2 = (val & 0xf0000000) >> 28; ptr = -1; for (j = 0; j < n && ptr == -1; j++) @@ -396,7 +443,7 @@ snd_installed_cards[ptr].config.io_base = ioaddr; snd_installed_cards[ptr].config.irq = irq; snd_installed_cards[ptr].config.dma = dma; - snd_installed_cards[ptr].config.dma2 = -1; + snd_installed_cards[ptr].config.dma2 = dma2; snd_installed_cards[ptr].config.name = NULL; snd_installed_cards[ptr].config.always_detect = 0; snd_installed_cards[ptr].config.driver_use_1 = 0; @@ -424,4 +471,131 @@ return (struct address_info *) NULL; return &snd_installed_cards[ptr].config; +} + + + +int +sound_install_audiodrv (int vers, + char *name, + struct audio_driver *driver, + int driver_size, + int flags, + unsigned int format_mask, + void *devc, + int dma1, + int dma2) +{ + struct audio_driver *d; + struct audio_operations *op; + int l, num; + + if (num_audiodevs >= MAX_AUDIO_DEV) + { + printk ("Sound: Too many audio drivers\n"); + return -(EIO); + } + + if (vers != AUDIO_DRIVER_VERSION || + driver_size > sizeof (struct audio_driver)) + { + printk ("Sound: Incompatible audio driver for %s\n", name); + return -(EIO); + } + + + d = (struct audio_driver *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct audio_driver))); + + if (sound_nblocks < 1024) + sound_nblocks++;; + + op = (struct audio_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct audio_operations))); + + if (sound_nblocks < 1024) + sound_nblocks++;; + if (d == NULL || op == NULL) + { + printk ("Sound: Can't allocate driver for (%s)\n", name); + return -(ENOSPC); + } + + memset ((char *) op, 0, sizeof (struct audio_operations)); + if (driver_size < sizeof (struct audio_driver)) + memset ((char *) d, 0, sizeof (struct audio_driver)); + + memcpy ((char *) d, (char *) driver, driver_size); + + op->d = d; + + l = strlen (name) + 1; + if (l > sizeof (op->name)) + l = sizeof (op->name); + strncpy (op->name, name, l); + op->name[l - 1] = 0; + op->flags = flags; + op->format_mask = format_mask; + op->devc = devc; + op->dmachan1 = dma1; + op->dmachan2 = dma2; + +/* + * Hardcoded defaults + */ + op->buffsize = DSP_BUFFSIZE; + + audio_devs[num_audiodevs] = op; + num = num_audiodevs++; + + DMAbuf_init (); + audio_init (); + return num; +} + +int +sound_install_mixer (int vers, + char *name, + struct mixer_operations *driver, + int driver_size, + void *devc) +{ + struct mixer_operations *op; + int l; + + if (num_mixers >= MAX_MIXER_DEV) + { + printk ("Sound: Too many mixer drivers\n"); + return -(EIO); + } + + if (vers != MIXER_DRIVER_VERSION || + driver_size > sizeof (struct mixer_operations)) + { + printk ("Sound: Incompatible mixer driver for %s\n", name); + return -(EIO); + } + + + op = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct mixer_operations))); + + if (sound_nblocks < 1024) + sound_nblocks++;; + if (op == NULL) + { + printk ("Sound: Can't allocate mixer driver for (%s)\n", name); + return -(ENOSPC); + } + + memset ((char *) op, 0, sizeof (struct mixer_operations)); + + memcpy ((char *) op, (char *) driver, driver_size); + + l = strlen (name) + 1; + if (l > sizeof (op->name)) + l = sizeof (op->name); + strncpy (op->name, name, l); + op->name[l - 1] = 0; + op->devc = devc; + + mixer_devs[num_mixers] = op; + return num_mixers++; } diff -ur --new-file old/linux/drivers/sound/dev_table.h new/linux/drivers/sound/dev_table.h --- old/linux/drivers/sound/dev_table.h Fri Apr 12 08:49:42 1996 +++ new/linux/drivers/sound/dev_table.h Sun Jul 7 10:18:51 1996 @@ -4,33 +4,24 @@ * Global definitions for device call tables */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ #ifndef _DEV_TABLE_H_ #define _DEV_TABLE_H_ + +/* + * Sound card numbers 27 to 999. (1 to 26 are defined in soundcard.h) + * Numbers 1000 to N are reserved for driver's internal use. + */ +#define SNDCARD_DESKPROXL 27 /* Compaq Deskpro XL */ + /* * NOTE! NOTE! NOTE! NOTE! * @@ -46,7 +37,7 @@ int card_subtype; /* Driver specific. Usually 0 */ int card_type; /* From soundcard.h */ char *name; - long (*attach) (long mem_start, struct address_info *hw_config); + void (*attach) (struct address_info *hw_config); int (*probe) (struct address_info *hw_config); void (*unload) (struct address_info *hw_config); }; @@ -143,16 +134,7 @@ void *devc; /* Driver specific info */ } coproc_operations; -struct audio_operations { - char name[32]; - int flags; -#define NOTHING_SPECIAL 0 -#define NEEDS_RESTART 1 -#define DMA_AUTOMODE 2 -#define DMA_DUPLEX 4 -#define DMA_PSEUDO_AUTOMODE 8 - int format_mask; /* Bitmask for supported audio formats */ - void *devc; /* Driver specific info */ +struct audio_driver { int (*open) (int dev, int mode); void (*close) (int dev); void (*output_block) (int dev, unsigned long buf, @@ -170,6 +152,23 @@ void (*halt_input) (int dev); void (*halt_output) (int dev); void (*trigger) (int dev, int bits); + int (*set_speed)(int dev, int speed); + unsigned int (*set_bits)(int dev, unsigned int bits); + short (*set_channels)(int dev, short channels); +}; + +struct audio_operations { + char name[32]; + int flags; +#define NOTHING_SPECIAL 0x00 +#define NEEDS_RESTART 0x01 +#define DMA_AUTOMODE 0x02 +#define DMA_DUPLEX 0x04 +#define DMA_PSEUDO_AUTOMODE 0x08 +#define DMA_HARDSTOP 0x10 + int format_mask; /* Bitmask for supported audio formats */ + void *devc; /* Driver specific info */ + struct audio_driver *d; long buffsize; int dmachan1, dmachan2; struct dma_buffparms *dmap_in, *dmap_out; @@ -178,11 +177,15 @@ int enable_bits; int open_mode; int go; + int min_fragment; /* 0 == unlimited */ }; struct mixer_operations { + char id[16]; char name[32]; int (*ioctl) (int dev, unsigned int cmd, caddr_t arg); + + void *devc; }; struct synth_operations { @@ -246,6 +249,7 @@ int (*buffer_status) (int dev); int (*prefix_cmd) (int dev, unsigned char status); struct coproc_operations *coproc; + void *devc; }; struct sound_lowlev_timer { @@ -290,7 +294,7 @@ struct driver_info sound_drivers[] = { #ifdef CONFIG_PSS - {"PSSECHO", 0, SNDCARD_PSS, "Echo Personal Sound System PSS (ESC614)", attach_pss, probe_pss, unload_pss}, + {"PSS", 0, SNDCARD_PSS, "Echo Personal Sound System PSS (ESC614)", attach_pss, probe_pss, unload_pss}, {"PSSMPU", 0, SNDCARD_PSS_MPU, "PSS-MPU", attach_pss_mpu, probe_pss_mpu, unload_pss_mpu}, {"PSSMSS", 0, SNDCARD_PSS_MSS, "PSS-MSS", attach_pss_mss, probe_pss_mss, unload_pss_mss}, #endif @@ -298,6 +302,8 @@ {"MSS", 0, SNDCARD_MSS, "MS Sound System", attach_ms_sound, probe_ms_sound, unload_ms_sound}, /* MSS without IRQ/DMA config registers (for DEC Alphas) */ {"PCXBJ", 1, SNDCARD_PSEUDO_MSS, "MS Sound System (AXP)", attach_ms_sound, probe_ms_sound, unload_ms_sound}, + /* Compaq Deskpro XL */ + {"DESKPROXL", 2, SNDCARD_DESKPROXL, "Compaq Deskpro XL", attach_ms_sound, probe_ms_sound, unload_ms_sound}, #endif #ifdef CONFIG_MAD16 {"MAD16", 0, SNDCARD_MAD16, "MAD16/Mozart (MSS)", attach_mad16, probe_mad16, unload_mad16}, @@ -323,12 +329,9 @@ {"MIDI6850", 0, SNDCARD_UART6850,"6860 UART Midi", attach_uart6850, probe_uart6850, unload_uart6850}, #endif #ifdef CONFIG_SB - {"SBLAST", 0, SNDCARD_SB, "SoundBlaster", attach_sb_card, probe_sb, unload_sb}, -#ifdef CONFIG_AUDIO - {"SBX", 0, SNDCARD_SB16, "SoundBlaster 16bit", sb16_dsp_init, sb16_dsp_detect, unload_sb16}, -#endif + {"SBLAST", 0, SNDCARD_SB, "Sound Blaster", attach_sb_card, probe_sb, unload_sb}, #ifdef CONFIG_MIDI - {"SBMPU", 0, SNDCARD_SB16MIDI,"SB MPU", attach_sb16midi, probe_sb16midi, unload_sb16midi}, + {"SBMPU", 0, SNDCARD_SB16MIDI,"SB MPU-401", attach_sbmpu, probe_sbmpu, unload_sbmpu}, #endif #endif #ifdef CONFIG_GUS16 @@ -339,16 +342,13 @@ {"GUSPNP", 1, SNDCARD_GUSPNP, "GUS PnP", attach_gus_card, probe_gus, unload_gus}, #endif #ifdef CONFIG_SSCAPE - {"SSCAPE", 0, SNDCARD_SSCAPE, "Ensoniq Soundscape", attach_sscape, probe_sscape, unload_sscape}, + {"SSCAPE", 0, SNDCARD_SSCAPE, "Ensoniq SoundScape", attach_sscape, probe_sscape, unload_sscape}, {"SSCAPEMSS", 0, SNDCARD_SSCAPE_MSS, "MS Sound System (SoundScape)", attach_ss_ms_sound, probe_ss_ms_sound, unload_ss_ms_sound}, #endif #ifdef CONFIG_TRIX - {"TRXPRO", 0, SNDCARD_TRXPRO, "MediaTriX AudioTriX Pro", attach_trix_wss, probe_trix_wss, unload_trix_wss}, - {"TRXPROSB", 0, SNDCARD_TRXPRO_SB, "AudioTriX (SB mode)", attach_trix_sb, probe_trix_sb, unload_trix_sb}, - {"TRXPROMPU", 0, SNDCARD_TRXPRO_MPU, "AudioTriX MIDI", attach_trix_mpu, probe_trix_mpu, unload_trix_mpu}, -#endif -#ifdef CONFIG_SPNP - {"AD1848", 0, 500, "SoundPort", attach_pnp_ad1848, probe_pnp_ad1848, unload_pnp_ad1848}, + {"TRXPRO", 0, SNDCARD_TRXPRO, "MediaTrix AudioTrix Pro", attach_trix_wss, probe_trix_wss, unload_trix_wss}, + {"TRXPROSB", 0, SNDCARD_TRXPRO_SB, "AudioTrix (SB mode)", attach_trix_sb, probe_trix_sb, unload_trix_sb}, + {"TRXPROMPU", 0, SNDCARD_TRXPRO_MPU, "AudioTrix MIDI", attach_trix_mpu, probe_trix_mpu, unload_trix_mpu}, #endif {NULL, 0, 0, "*?*", NULL, NULL, NULL} }; @@ -390,7 +390,7 @@ #endif #ifdef CONFIG_SSCAPE {SNDCARD_SSCAPE, {SSCAPE_BASE, SSCAPE_IRQ, SSCAPE_DMA, -1}, SND_DEFAULT_ENABLE}, - {SNDCARD_SSCAPE_MSS, {SSCAPE_MSS_BASE, SSCAPE_MSS_IRQ, SSCAPE_MSS_DMA, -1}, SND_DEFAULT_ENABLE}, + {SNDCARD_SSCAPE_MSS, {SSCAPE_MSS_BASE, SSCAPE_MSS_IRQ, SSCAPE_DMA, -1}, SND_DEFAULT_ENABLE}, #endif #ifdef CONFIG_MAD16 #ifndef MAD16_DMA2 @@ -412,13 +412,19 @@ {SNDCARD_CS4232, {CS4232_BASE, CS4232_IRQ, CS4232_DMA, CS4232_DMA2}, SND_DEFAULT_ENABLE}, #endif + #ifdef CONFIG_MSS +# ifdef DESKPROXL + {SNDCARD_DESKPROXL, {MSS_BASE, MSS_IRQ, MSS_DMA, -1}, SND_DEFAULT_ENABLE}, +# else {SNDCARD_MSS, {MSS_BASE, MSS_IRQ, MSS_DMA, -1}, SND_DEFAULT_ENABLE}, +# endif # ifdef MSS2_BASE {SNDCARD_MSS, {MSS2_BASE, MSS2_IRQ, MSS2_DMA, -1}, SND_DEFAULT_ENABLE}, # endif #endif + #ifdef CONFIG_PAS {SNDCARD_PAS, {PAS_BASE, PAS_IRQ, PAS_DMA, -1}, SND_DEFAULT_ENABLE}, #endif @@ -431,6 +437,9 @@ # define SB_DMA2 -1 # endif {SNDCARD_SB, {SBC_BASE, SBC_IRQ, SBC_DMA, SB_DMA2}, SND_DEFAULT_ENABLE}, +# ifdef SB2_BASE + {SNDCARD_SB, {SB2_BASE, SB2_IRQ, SB2_DMA, SB2_DMA2}, SND_DEFAULT_ENABLE}, +# endif #endif #if defined(CONFIG_MAUI) {SNDCARD_MAUI, {MAUI_BASE, MAUI_IRQ, 0, -1}, SND_DEFAULT_ENABLE}, @@ -508,8 +517,9 @@ extern int max_sound_cards; extern int trace_init; +#endif /* _DEV_TABLE_C_ */ -long sndtable_init(long mem_start); +void sndtable_init(void); int sndtable_get_cardcount (void); struct address_info *sound_getconf(int card_type); void sound_chconf(int card_type, int ioaddr, int irq, int dma); @@ -525,11 +535,28 @@ void install_pnp_sounddrv(struct pnp_sounddev *drv); int sndtable_probe (int unit, struct address_info *hw_config); int sndtable_init_card (int unit, struct address_info *hw_config); +int sndtable_start_card (int unit, struct address_info *hw_config); void sound_timer_init (struct sound_lowlev_timer *t, char *name); int sound_start_dma ( int dev, struct dma_buffparms *dmap, int chan, unsigned long physaddr, int count, int dma_mode, int autoinit); void sound_dma_intr (int dev, struct dma_buffparms *dmap, int chan); -#endif /* _DEV_TABLE_C_ */ +#define AUDIO_DRIVER_VERSION 1 +#define MIXER_DRIVER_VERSION 1 +int sound_install_audiodrv(int vers, + char *name, + struct audio_driver *driver, + int driver_size, + int flags, + unsigned int format_mask, + void *devc, + int dma1, + int dma2); +int sound_install_mixer(int vers, + char *name, + struct mixer_operations *driver, + int driver_size, + void *devc); + #endif /* _DEV_TABLE_H_ */ diff -ur --new-file old/linux/drivers/sound/dmabuf.c new/linux/drivers/sound/dmabuf.c --- old/linux/drivers/sound/dmabuf.c Thu Apr 18 07:22:20 1996 +++ new/linux/drivers/sound/dmabuf.c Sun Aug 18 09:46:48 1996 @@ -4,27 +4,11 @@ * The DMA buffer manager for digitized voice applications */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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 @@ -59,6 +43,7 @@ static void dma_reset_output (int dev); static void dma_reset_input (int dev); +static int dma_set_fragment (int dev, struct dma_buffparms *dmap, caddr_t arg, int fact); static void reorganize_buffers (int dev, struct dma_buffparms *dmap, int recording) @@ -75,9 +60,9 @@ if (dmap->fragment_size == 0) { /* Compute the fragment size using the default algorithm */ - sr = dsp_dev->ioctl (dev, SOUND_PCM_READ_RATE, 0, 1); - nc = dsp_dev->ioctl (dev, SOUND_PCM_READ_CHANNELS, 0, 1); - sz = dsp_dev->ioctl (dev, SOUND_PCM_READ_BITS, 0, 1); + sr = dsp_dev->d->set_speed (dev, 0); + nc = dsp_dev->d->set_channels (dev, 0); + sz = dsp_dev->d->set_bits (dev, 0); if (sz == 8) dmap->neutral_byte = NEUTRAL8; @@ -156,9 +141,10 @@ dmap->nbufs = n; dmap->bytes_in_use = n * bsz; - memset (dmap->raw_buf, - dmap->neutral_byte, - dmap->bytes_in_use); + if (dmap->raw_buf) + memset (dmap->raw_buf, + dmap->neutral_byte, + dmap->bytes_in_use); for (i = 0; i < dmap->nbufs; i++) { @@ -173,11 +159,11 @@ { if (dmap == audio_devs[dev]->dmap_out) { - out_sleep_flag[dev].mode = WK_NONE; + out_sleep_flag[dev].flags = WK_NONE; } else { - in_sleep_flag[dev].mode = WK_NONE; + in_sleep_flag[dev].flags = WK_NONE; } dmap->flags = DMA_BUSY; /* Other flags off */ @@ -196,7 +182,7 @@ open_dmap (int dev, int mode, struct dma_buffparms *dmap, int chan) { if (dmap->flags & DMA_BUSY) - return -EBUSY; + return -(EBUSY); { int err; @@ -206,12 +192,12 @@ } if (dmap->raw_buf == NULL) - return -ENOSPC; /* Memory allocation failed during boot */ + return -(ENOSPC); /* Memory allocation failed during boot */ if (sound_open_dma (chan, audio_devs[dev]->name)) { printk ("Unable to grab(2) DMA%d for the audio driver\n", chan); - return -EBUSY; + return -(EBUSY); } dmap->open_mode = mode; @@ -238,6 +224,37 @@ sound_free_dmap (dev, dmap); } +static unsigned int +default_set_bits (int dev, unsigned int bits) +{ + return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SETFMT, (caddr_t) (long) bits, 1); +} + +static int +default_set_speed (int dev, int speed) +{ + return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_SPEED, (caddr_t) (long) speed, 1); +} + +static short +default_set_channels (int dev, short channels) +{ + int c = channels; + + return audio_devs[dev]->d->ioctl (dev, SNDCTL_DSP_CHANNELS, (caddr_t) (long) c, 1); +} + +static void +check_driver (struct audio_driver *d) +{ + if (d->set_speed == NULL) + d->set_speed = default_set_speed; + if (d->set_bits == NULL) + d->set_bits = default_set_bits; + if (d->set_channels == NULL) + d->set_channels = default_set_channels; +} + int DMAbuf_open (int dev, int mode) { @@ -247,14 +264,14 @@ if (dev >= num_audiodevs) { - printk ("PCM device %d not installed.\n", dev); - return -ENXIO; + /* printk ("PCM device %d not installed.\n", dev); */ + return -(ENXIO); } if (!audio_devs[dev]) { - printk ("PCM device %d not initialized\n", dev); - return -ENXIO; + /* printk ("PCM device %d not initialized\n", dev); */ + return -(ENXIO); } if (!(audio_devs[dev]->flags & DMA_DUPLEX)) @@ -263,34 +280,37 @@ audio_devs[dev]->dmachan2 = audio_devs[dev]->dmachan1; } - if ((retval = audio_devs[dev]->open (dev, mode)) < 0) + if ((retval = audio_devs[dev]->d->open (dev, mode)) < 0) return retval; + check_driver (audio_devs[dev]->d); + dmap_out = audio_devs[dev]->dmap_out; dmap_in = audio_devs[dev]->dmap_in; if ((retval = open_dmap (dev, mode, dmap_out, audio_devs[dev]->dmachan1)) < 0) { - audio_devs[dev]->close (dev); + audio_devs[dev]->d->close (dev); return retval; } audio_devs[dev]->enable_bits = mode; - if (audio_devs[dev]->flags & DMA_DUPLEX && dmap_out != dmap_in) + if (mode & OPEN_READ && + audio_devs[dev]->flags & DMA_DUPLEX && dmap_out != dmap_in) if ((retval = open_dmap (dev, mode, dmap_in, audio_devs[dev]->dmachan2)) < 0) { - audio_devs[dev]->close (dev); + audio_devs[dev]->d->close (dev); close_dmap (dev, dmap_out, audio_devs[dev]->dmachan1); return retval; } audio_devs[dev]->open_mode = mode; audio_devs[dev]->go = 1; - in_sleep_flag[dev].mode = WK_NONE; - out_sleep_flag[dev].mode = WK_NONE; + in_sleep_flag[dev].flags = WK_NONE; + out_sleep_flag[dev].flags = WK_NONE; - audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_BITS, (caddr_t) 8, 1); - audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_CHANNELS, (caddr_t) 1, 1); - audio_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_RATE, (caddr_t) DSP_DEFAULT_SPEED, 1); + audio_devs[dev]->d->set_bits (dev, 8); + audio_devs[dev]->d->set_channels (dev, 1); + audio_devs[dev]->d->set_speed (dev, DSP_DEFAULT_SPEED); return 0; } @@ -302,12 +322,13 @@ save_flags (flags); cli (); - audio_devs[dev]->reset (dev); + audio_devs[dev]->d->reset (dev); restore_flags (flags); dma_reset_output (dev); - if (audio_devs[dev]->flags & DMA_DUPLEX) + if (audio_devs[dev]->flags & DMA_DUPLEX && + audio_devs[dev]->open_mode & OPEN_READ) dma_reset_input (dev); } @@ -319,10 +340,10 @@ save_flags (flags); cli (); if (!(audio_devs[dev]->flags & DMA_DUPLEX) || - !audio_devs[dev]->halt_output) - audio_devs[dev]->reset (dev); + !audio_devs[dev]->d->halt_output) + audio_devs[dev]->d->reset (dev); else - audio_devs[dev]->halt_output (dev); + audio_devs[dev]->d->halt_output (dev); restore_flags (flags); dma_init_buffers (dev, audio_devs[dev]->dmap_out); @@ -337,10 +358,10 @@ save_flags (flags); cli (); if (!(audio_devs[dev]->flags & DMA_DUPLEX) || - !audio_devs[dev]->halt_input) - audio_devs[dev]->reset (dev); + !audio_devs[dev]->d->halt_input) + audio_devs[dev]->d->reset (dev); else - audio_devs[dev]->halt_input (dev); + audio_devs[dev]->d->halt_input (dev); restore_flags (flags); dma_init_buffers (dev, audio_devs[dev]->dmap_in); @@ -360,7 +381,7 @@ save_flags (flags); cli (); - audio_devs[dev]->flags |= DMA_SYNCING; + audio_devs[dev]->dmap_out->flags |= DMA_SYNCING; audio_devs[dev]->dmap_out->underrun_count = 0; while (!current_got_fatal_signal () @@ -369,29 +390,29 @@ { { - unsigned long tl; + unsigned long tlimit; if (HZ) - current_set_timeout (tl = jiffies + (HZ)); + current_set_timeout (tlimit = jiffies + (HZ)); else - tl = (unsigned long) -1; - out_sleep_flag[dev].mode = WK_SLEEP; + tlimit = (unsigned long) -1; + out_sleep_flag[dev].flags = WK_SLEEP; module_interruptible_sleep_on (&out_sleeper[dev]); - if (!(out_sleep_flag[dev].mode & WK_WAKEUP)) + if (!(out_sleep_flag[dev].flags & WK_WAKEUP)) { - if (jiffies >= tl) - out_sleep_flag[dev].mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + out_sleep_flag[dev].flags |= WK_TIMEOUT; } - out_sleep_flag[dev].mode &= ~WK_SLEEP; + out_sleep_flag[dev].flags &= ~WK_SLEEP; }; - if ((out_sleep_flag[dev].mode & WK_TIMEOUT)) + if ((out_sleep_flag[dev].flags & WK_TIMEOUT)) { - audio_devs[dev]->flags &= ~DMA_SYNCING; + audio_devs[dev]->dmap_out->flags &= ~DMA_SYNCING; restore_flags (flags); return audio_devs[dev]->dmap_out->qlen; } } - audio_devs[dev]->flags &= ~DMA_SYNCING; + audio_devs[dev]->dmap_out->flags &= ~DMA_SYNCING; restore_flags (flags); /* @@ -401,27 +422,27 @@ save_flags (flags); cli (); - if (audio_devs[dev]->local_qlen) /* Device has hidden buffers */ + if (audio_devs[dev]->d->local_qlen) /* Device has hidden buffers */ { while (!(current_got_fatal_signal ()) - && audio_devs[dev]->local_qlen (dev)) + && audio_devs[dev]->d->local_qlen (dev)) { { - unsigned long tl; + unsigned long tlimit; if (HZ) - current_set_timeout (tl = jiffies + (HZ)); + current_set_timeout (tlimit = jiffies + (HZ)); else - tl = (unsigned long) -1; - out_sleep_flag[dev].mode = WK_SLEEP; + tlimit = (unsigned long) -1; + out_sleep_flag[dev].flags = WK_SLEEP; module_interruptible_sleep_on (&out_sleeper[dev]); - if (!(out_sleep_flag[dev].mode & WK_WAKEUP)) + if (!(out_sleep_flag[dev].flags & WK_WAKEUP)) { - if (jiffies >= tl) - out_sleep_flag[dev].mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + out_sleep_flag[dev].flags |= WK_TIMEOUT; } - out_sleep_flag[dev].mode &= ~WK_SLEEP; + out_sleep_flag[dev].flags &= ~WK_SLEEP; }; } } @@ -442,20 +463,23 @@ && (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT)) { dma_sync (dev); - - memset (audio_devs[dev]->dmap_out->raw_buf, - audio_devs[dev]->dmap_out->neutral_byte, - audio_devs[dev]->dmap_out->bytes_in_use); } + if (audio_devs[dev]->dmap_out->dma_mode == DMODE_OUTPUT) + memset (audio_devs[dev]->dmap_out->raw_buf, + audio_devs[dev]->dmap_out->neutral_byte, + audio_devs[dev]->dmap_out->bytes_in_use); + save_flags (flags); cli (); - audio_devs[dev]->close (dev); + audio_devs[dev]->d->halt_xfer (dev); + audio_devs[dev]->d->close (dev); close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1); - if (audio_devs[dev]->flags & DMA_DUPLEX) + if (audio_devs[dev]->open_mode & OPEN_READ && + audio_devs[dev]->flags & DMA_DUPLEX) close_dmap (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2); audio_devs[dev]->open_mode = 0; @@ -467,6 +491,8 @@ static int activate_recording (int dev, struct dma_buffparms *dmap) { + int prepare = 0; + if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT)) return 0; @@ -474,6 +500,7 @@ { dma_reset_input (dev); dmap->flags &= ~DMA_RESTART; + prepare = 1; } if (dmap->dma_mode == DMODE_OUTPUT) /* Direction change */ @@ -486,11 +513,11 @@ if (!(dmap->flags & DMA_ALLOC_DONE)) reorganize_buffers (dev, dmap, 1); - if (!dmap->dma_mode) + if (prepare || !dmap->dma_mode) { int err; - if ((err = audio_devs[dev]->prepare_for_input (dev, + if ((err = audio_devs[dev]->d->prepare_for_input (dev, dmap->fragment_size, dmap->nbufs)) < 0) { return err; @@ -500,14 +527,14 @@ if (!(dmap->flags & DMA_ACTIVE)) { - audio_devs[dev]->start_input (dev, dmap->raw_buf_phys + - dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 0, + audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys + + dmap->qtail * dmap->fragment_size, + dmap->fragment_size, 0, !(audio_devs[dev]->flags & DMA_AUTOMODE) || - !(dmap->flags & DMA_STARTED)); + !(dmap->flags & DMA_STARTED)); dmap->flags |= DMA_ACTIVE | DMA_STARTED; - if (audio_devs[dev]->trigger) - audio_devs[dev]->trigger (dev, + if (audio_devs[dev]->d->trigger) + audio_devs[dev]->d->trigger (dev, audio_devs[dev]->enable_bits * audio_devs[dev]->go); } return 0; @@ -525,7 +552,7 @@ if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) { printk ("Sound: Can't read from mmapped device (1)\n"); - return -EINVAL; + return -(EINVAL); } else if (!dmap->qlen) { @@ -542,43 +569,43 @@ if (dontblock) { restore_flags (flags); - return -EAGAIN; + return -(EAGAIN); } if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_INPUT) & audio_devs[dev]->go) { restore_flags (flags); - return -EAGAIN; + return -(EAGAIN); } if (!audio_devs[dev]->go) tmout = 0; else - tmout = 2 * HZ; + tmout = 10 * HZ; { - unsigned long tl; + unsigned long tlimit; if (tmout) - current_set_timeout (tl = jiffies + (tmout)); + current_set_timeout (tlimit = jiffies + (tmout)); else - tl = (unsigned long) -1; - in_sleep_flag[dev].mode = WK_SLEEP; + tlimit = (unsigned long) -1; + in_sleep_flag[dev].flags = WK_SLEEP; module_interruptible_sleep_on (&in_sleeper[dev]); - if (!(in_sleep_flag[dev].mode & WK_WAKEUP)) + if (!(in_sleep_flag[dev].flags & WK_WAKEUP)) { - if (jiffies >= tl) - in_sleep_flag[dev].mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + in_sleep_flag[dev].flags |= WK_TIMEOUT; } - in_sleep_flag[dev].mode &= ~WK_SLEEP; + in_sleep_flag[dev].flags &= ~WK_SLEEP; }; - if ((in_sleep_flag[dev].mode & WK_TIMEOUT)) + if ((in_sleep_flag[dev].flags & WK_TIMEOUT)) { printk ("Sound: DMA (input) timed out - IRQ/DRQ config error?\n"); err = EIO; - audio_devs[dev]->reset (dev); + audio_devs[dev]->d->reset (dev); ; } else @@ -587,7 +614,7 @@ restore_flags (flags); if (!dmap->qlen) - return -err; + return -(err); *buf = &dmap->raw_buf[dmap->qhead * dmap->fragment_size + dmap->counts[dmap->qhead]]; *len = dmap->fragment_size - dmap->counts[dmap->qhead]; @@ -605,7 +632,7 @@ if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) { printk ("Sound: Can't read from mmapped device (2)\n"); - return -EINVAL; + return -(EINVAL); } else if (p >= dmap->fragment_size) { /* This buffer is completely empty */ @@ -635,13 +662,13 @@ if (dmap->subdivision != 0 || dmap->fragment_size) /* Too late to change */ - return -EINVAL; + return -(EINVAL); if (fact > MAX_REALTIME_FACTOR) - return -EINVAL; + return -(EINVAL); if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact != 16) - return -EINVAL; + return -(EINVAL); dmap->subdivision = fact; return snd_ioctl_return ((int *) arg, fact); @@ -653,23 +680,27 @@ int bytes, count; if (fact == 0) - return -EIO; + return -(EIO); if (dmap->subdivision != 0 || dmap->fragment_size) /* Too late to change */ - return -EINVAL; + return -(EINVAL); bytes = fact & 0xffff; - count = (fact >> 16) & 0xffff; + count = (fact >> 16) & 0x7fff; if (count == 0) count = MAX_SUB_BUFFERS; - if (bytes < 4 || bytes > 17) /* <16 || > 128k */ - return -EINVAL; + if (bytes < 4 || bytes > 17) /* <16 || > 512k */ + return -(EINVAL); if (count < 2) - return -EINVAL; + return -(EINVAL); + + if (audio_devs[dev]->min_fragment > 0) + if (bytes < audio_devs[dev]->min_fragment) + bytes = audio_devs[dev]->min_fragment; #ifdef OS_DMA_MINBITS if (bytes < OS_DMA_MINBITS) @@ -687,7 +718,10 @@ dmap->fragment_size /= 2; /* Needs at least 2 buffers */ dmap->subdivision = 1; /* Disable SNDCTL_DSP_SUBDIVIDE */ - return snd_ioctl_return ((int *) arg, bytes | (count << 16)); + if (arg) + return snd_ioctl_return ((int *) arg, bytes | (count << 16)); + else + return 0; } static int @@ -727,9 +761,45 @@ { struct dma_buffparms *dmap_out = audio_devs[dev]->dmap_out; struct dma_buffparms *dmap_in = audio_devs[dev]->dmap_in; + long larg = (long) arg; switch (cmd) { + case SOUND_PCM_WRITE_RATE: + if (local) + return audio_devs[dev]->d->set_speed (dev, larg); + return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_speed (dev, get_user ((int *) arg))); + + case SOUND_PCM_READ_RATE: + if (local) + return audio_devs[dev]->d->set_speed (dev, 0); + return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_speed (dev, 0)); + + case SNDCTL_DSP_STEREO: + if (local) + return audio_devs[dev]->d->set_channels (dev, larg + 1) - 1; + return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_channels (dev, get_user ((int *) arg) + 1) - 1); + + case SOUND_PCM_WRITE_CHANNELS: + if (local) + return audio_devs[dev]->d->set_channels (dev, (short) larg); + return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_channels (dev, get_user ((int *) arg))); + + case SOUND_PCM_READ_CHANNELS: + if (local) + return audio_devs[dev]->d->set_channels (dev, 0); + return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_channels (dev, 0)); + + case SNDCTL_DSP_SAMPLESIZE: + if (local) + return audio_devs[dev]->d->set_bits (dev, larg); + return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_bits (dev, get_user ((int *) arg))); + + case SOUND_PCM_READ_BITS: + if (local) + return audio_devs[dev]->d->set_bits (dev, 0); + return snd_ioctl_return ((int *) arg, audio_devs[dev]->d->set_bits (dev, 0)); + case SNDCTL_DSP_RESET: dma_reset (dev); return 0; @@ -746,7 +816,8 @@ { reorganize_buffers (dev, dmap_out, (audio_devs[dev]->open_mode == OPEN_READ)); - if (audio_devs[dev]->flags & DMA_DUPLEX) + if (audio_devs[dev]->flags & DMA_DUPLEX && + audio_devs[dev]->open_mode & OPEN_READ) reorganize_buffers (dev, dmap_in, (audio_devs[dev]->open_mode == OPEN_READ)); } @@ -756,14 +827,15 @@ case SNDCTL_DSP_SUBDIVIDE: { - int fact = get_fs_long ((long *) arg); + int fact = get_user ((int *) arg); int ret; ret = dma_subdivide (dev, dmap_out, arg, fact); if (ret < 0) return ret; - if (audio_devs[dev]->flags & DMA_DUPLEX) + if (audio_devs[dev]->flags & DMA_DUPLEX && + audio_devs[dev]->open_mode & OPEN_READ) ret = dma_subdivide (dev, dmap_in, arg, fact); return ret; @@ -772,21 +844,22 @@ case SNDCTL_DSP_SETDUPLEX: if (audio_devs[dev]->flags & DMA_DUPLEX) - return 0; + return 0; else - return -EIO; + return -(EIO); break; case SNDCTL_DSP_SETFRAGMENT: { - int fact = get_fs_long ((long *) arg); + int fact = get_user ((int *) arg); int ret; ret = dma_set_fragment (dev, dmap_out, arg, fact); if (ret < 0) return ret; - if (audio_devs[dev]->flags & DMA_DUPLEX) + if (audio_devs[dev]->flags & DMA_DUPLEX && + audio_devs[dev]->open_mode & OPEN_READ) ret = dma_set_fragment (dev, dmap_in, arg, fact); return ret; @@ -796,18 +869,22 @@ case SNDCTL_DSP_GETISPACE: case SNDCTL_DSP_GETOSPACE: if (!local) - return -EINVAL; + return -(EINVAL); else { struct dma_buffparms *dmap = dmap_out; audio_buf_info *info = (audio_buf_info *) arg; + if (cmd == SNDCTL_DSP_GETISPACE && + !(audio_devs[dev]->open_mode & OPEN_READ)) + return -(EINVAL); + if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX) dmap = dmap_in; if (dmap->mapping_flags & DMA_MAP_MAPPED) - return -EINVAL; + return -(EINVAL); if (!(dmap->flags & DMA_ALLOC_DONE)) reorganize_buffers (dev, dmap, (cmd == SNDCTL_DSP_GETISPACE)); @@ -823,9 +900,9 @@ else { info->fragments = dmap->nbufs - dmap->qlen; - if (audio_devs[dev]->local_qlen) + if (audio_devs[dev]->d->local_qlen) { - int tmp = audio_devs[dev]->local_qlen (dev); + int tmp = audio_devs[dev]->d->local_qlen (dev); if (tmp && info->fragments) tmp--; /* @@ -853,17 +930,17 @@ { unsigned long flags; - int bits = get_fs_long ((long *) arg) & audio_devs[dev]->open_mode; + int bits = get_user ((int *) arg) & audio_devs[dev]->open_mode; int changed; - if (audio_devs[dev]->trigger == NULL) - return -EINVAL; + if (audio_devs[dev]->d->trigger == NULL) + return -(EINVAL); if (!(audio_devs[dev]->flags & DMA_DUPLEX)) if ((bits & PCM_ENABLE_INPUT) && (bits & PCM_ENABLE_OUTPUT)) { printk ("Sound: Device doesn't have full duplex capability\n"); - return -EINVAL; + return -(EINVAL); } save_flags (flags); @@ -879,10 +956,11 @@ reorganize_buffers (dev, dmap_in, 1); } - if ((err = audio_devs[dev]->prepare_for_input (dev, + if ((err = audio_devs[dev]->d->prepare_for_input (dev, dmap_in->fragment_size, dmap_in->nbufs)) < 0) - return -err; + return -(err); + audio_devs[dev]->enable_bits = bits; activate_recording (dev, dmap_in); } @@ -897,17 +975,19 @@ reorganize_buffers (dev, dmap_out, 0); } - if ((err = audio_devs[dev]->prepare_for_output (dev, + if ((err = audio_devs[dev]->d->prepare_for_output (dev, dmap_out->fragment_size, dmap_out->nbufs)) < 0) - return -err; + return -(err); dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size; DMAbuf_start_output (dev, 0, dmap_out->fragment_size); } audio_devs[dev]->enable_bits = bits; - if (changed && audio_devs[dev]->trigger) - audio_devs[dev]->trigger (dev, bits * audio_devs[dev]->go); + if (changed && audio_devs[dev]->d->trigger) + { + audio_devs[dev]->d->trigger (dev, bits * audio_devs[dev]->go); + } restore_flags (flags); } case SNDCTL_DSP_GETTRIGGER: @@ -916,10 +996,10 @@ case SNDCTL_DSP_SETSYNCRO: - if (!audio_devs[dev]->trigger) - return -EINVAL; + if (!audio_devs[dev]->d->trigger) + return -(EINVAL); - audio_devs[dev]->trigger (dev, 0); + audio_devs[dev]->d->trigger (dev, 0); audio_devs[dev]->go = 0; return 0; break; @@ -929,13 +1009,16 @@ count_info info; unsigned long flags; + if (!(audio_devs[dev]->open_mode & OPEN_READ)) + return -(EINVAL); + save_flags (flags); cli (); info.bytes = audio_devs[dev]->dmap_in->byte_counter; info.ptr = get_buffer_pointer (dev, audio_devs[dev]->dmachan2, audio_devs[dev]->dmap_in); info.blocks = audio_devs[dev]->dmap_in->qlen; info.bytes += info.ptr; - memcpy_tofs ((&((char *) arg)[0]), (char *) &info, sizeof (info)); + memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info)); if (audio_devs[dev]->dmap_in->mapping_flags & DMA_MAP_MAPPED) audio_devs[dev]->dmap_in->qlen = 0; /* Acknowledge interrupts */ @@ -949,13 +1032,16 @@ count_info info; unsigned long flags; + if (!(audio_devs[dev]->open_mode & OPEN_WRITE)) + return -(EINVAL); + save_flags (flags); cli (); info.bytes = audio_devs[dev]->dmap_out->byte_counter; info.ptr = get_buffer_pointer (dev, audio_devs[dev]->dmachan1, audio_devs[dev]->dmap_out); info.blocks = audio_devs[dev]->dmap_out->qlen; info.bytes += info.ptr; - memcpy_tofs ((&((char *) arg)[0]), (char *) &info, sizeof (info)); + memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info)); if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED) audio_devs[dev]->dmap_out->qlen = 0; /* Acknowledge interrupts */ @@ -966,7 +1052,7 @@ default: - return audio_devs[dev]->ioctl (dev, cmd, arg, local); + return audio_devs[dev]->d->ioctl (dev, cmd, arg, local); } } @@ -989,8 +1075,8 @@ /* OK to start the device */ audio_devs[dev]->go = 1; - if (audio_devs[dev]->trigger) - audio_devs[dev]->trigger (dev, + if (audio_devs[dev]->d->trigger) + audio_devs[dev]->d->trigger (dev, audio_devs[dev]->enable_bits * audio_devs[dev]->go); } } @@ -1012,9 +1098,9 @@ max = dmap->max_fragments; len = dmap->qlen; - if (audio_devs[dev]->local_qlen) + if (audio_devs[dev]->d->local_qlen) { - tmp = audio_devs[dev]->local_qlen (dev); + tmp = audio_devs[dev]->d->local_qlen (dev); if (tmp && len) tmp--; /* * This buffer has been counted twice @@ -1039,7 +1125,7 @@ if (audio_devs[dev]->dmap_out->mapping_flags & DMA_MAP_MAPPED) { printk ("Sound: Can't write to mmapped device (3)\n"); - return -EINVAL; + return -(EINVAL); } if (dmap->dma_mode == DMODE_INPUT) /* Direction change */ @@ -1063,7 +1149,7 @@ int err; dmap->dma_mode = DMODE_OUTPUT; - if ((err = audio_devs[dev]->prepare_for_output (dev, + if ((err = audio_devs[dev]->d->prepare_for_output (dev, dmap->fragment_size, dmap->nbufs)) < 0) return err; } @@ -1080,14 +1166,14 @@ if (dontblock) { restore_flags (flags); - return -EAGAIN; + return -(EAGAIN); } if (!(audio_devs[dev]->enable_bits & PCM_ENABLE_OUTPUT) && audio_devs[dev]->go) { restore_flags (flags); - return -EAGAIN; + return -(EAGAIN); } /* @@ -1100,28 +1186,32 @@ { - unsigned long tl; + unsigned long tlimit; if (tmout) - current_set_timeout (tl = jiffies + (tmout)); + current_set_timeout (tlimit = jiffies + (tmout)); else - tl = (unsigned long) -1; - out_sleep_flag[dev].mode = WK_SLEEP; + tlimit = (unsigned long) -1; + out_sleep_flag[dev].flags = WK_SLEEP; module_interruptible_sleep_on (&out_sleeper[dev]); - if (!(out_sleep_flag[dev].mode & WK_WAKEUP)) + if (!(out_sleep_flag[dev].flags & WK_WAKEUP)) { - if (jiffies >= tl) - out_sleep_flag[dev].mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + out_sleep_flag[dev].flags |= WK_TIMEOUT; } - out_sleep_flag[dev].mode &= ~WK_SLEEP; + out_sleep_flag[dev].flags &= ~WK_SLEEP; }; - if ((out_sleep_flag[dev].mode & WK_TIMEOUT)) + if ((out_sleep_flag[dev].flags & WK_TIMEOUT)) { printk ("Sound: DMA (output) timed out - IRQ/DRQ config error?\n"); err = EIO; abort = 1; ; - audio_devs[dev]->reset (dev); + if (audio_devs[dev]->flags & DMA_AUTOMODE) + dmap->flags |= DMA_RESTART; + else + dmap->flags &= ~DMA_RESTART; + audio_devs[dev]->d->reset (dev); } else if (current_got_fatal_signal ()) { @@ -1133,7 +1223,7 @@ if (!space_in_queue (dev)) { - return -err; /* Caught a signal ? */ + return -(err); /* Caught a signal ? */ } *buf = dmap->raw_buf + dmap->qtail * dmap->fragment_size; @@ -1176,8 +1266,11 @@ DMAbuf_start_output (int dev, int buff_no, int l) { struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + int restart = 0; dmap->cfrag = -1; + if (dmap->flags & DMA_RESTART) + restart = 1; /* * Bypass buffering if using mmapped access @@ -1193,7 +1286,6 @@ else { - dmap->qlen++; if (dmap->qlen <= 0 || dmap->qlen > dmap->nbufs) printk ("\nSound: Audio queue2 corrupted for dev%d (%d/%d)\n", @@ -1204,10 +1296,15 @@ { int p = dmap->fragment_size * dmap->qtail; + dmap->neutral_byte = dmap->raw_buf[p + l - 1]; + memset (dmap->raw_buf + p + l, dmap->neutral_byte, dmap->fragment_size - l); } + else + dmap->neutral_byte = + dmap->raw_buf[dmap->fragment_size * dmap->qtail - 1]; if ((l != dmap->fragment_size) && ((audio_devs[dev]->flags & DMA_AUTOMODE) && @@ -1222,14 +1319,19 @@ if (!(dmap->flags & DMA_ACTIVE)) { dmap->flags |= DMA_ACTIVE; - audio_devs[dev]->output_block (dev, dmap->raw_buf_phys + - dmap->qhead * dmap->fragment_size, - dmap->counts[dmap->qhead], 0, + + if (restart) + audio_devs[dev]->d->prepare_for_output (dev, + dmap->fragment_size, dmap->nbufs); + + audio_devs[dev]->d->output_block (dev, dmap->raw_buf_phys + + dmap->qhead * dmap->fragment_size, + dmap->counts[dmap->qhead], 0, !(audio_devs[dev]->flags & DMA_AUTOMODE) || - !(dmap->flags & DMA_STARTED)); + !(dmap->flags & DMA_STARTED)); dmap->flags |= DMA_STARTED; - if (audio_devs[dev]->trigger) - audio_devs[dev]->trigger (dev, + if (audio_devs[dev]->d->trigger) + audio_devs[dev]->d->trigger (dev, audio_devs[dev]->enable_bits * audio_devs[dev]->go); } @@ -1254,6 +1356,12 @@ dmap = audio_devs[dev]->dmap_in; } + if (dmap->raw_buf_phys == 0) + { + printk ("sound: DMA buffer == NULL\n"); + return 0; + } + /* * The count must be one less than the actual size. This is handled by * set_dma_addr() @@ -1290,8 +1398,8 @@ return count; } -long -DMAbuf_init (long mem_start) +void +DMAbuf_init (void) { int dev; @@ -1311,7 +1419,6 @@ audio_devs[dev]->dmap_in = &dmaps[ndmaps++]; } - return mem_start; } static void @@ -1343,12 +1450,12 @@ force_restart (int dev, struct dma_buffparms *dmap) { if ((audio_devs[dev]->flags & DMA_DUPLEX) && - audio_devs[dev]->halt_output) - audio_devs[dev]->halt_output (dev); + audio_devs[dev]->d->halt_output) + audio_devs[dev]->d->halt_output (dev); else - audio_devs[dev]->halt_xfer (dev); + audio_devs[dev]->d->halt_xfer (dev); - dmap->flags &= ~DMA_ACTIVE; + dmap->flags &= ~(DMA_ACTIVE | DMA_STARTED); if (audio_devs[dev]->flags & DMA_AUTOMODE) dmap->flags |= DMA_RESTART; else @@ -1370,6 +1477,7 @@ unsigned long flags; struct dma_buffparms *dmap = audio_devs[dev]->dmap_out; + int this_fragment; dmap->byte_counter += dmap->counts[dmap->qhead]; @@ -1377,10 +1485,15 @@ sound_dma_intr (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1); #endif + if (dmap->raw_buf == NULL) + { + printk ("Sound: Fatal error. Audio interrupt after freeing buffers.\n"); + return; + } + if (dmap->mapping_flags & DMA_MAP_MAPPED) { /* mmapped access */ - dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; dmap->qlen++; /* Yes increment it (don't decrement) */ dmap->flags &= ~DMA_ACTIVE; @@ -1388,12 +1501,12 @@ if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) { - audio_devs[dev]->output_block (dev, dmap->raw_buf_phys + - dmap->qhead * dmap->fragment_size, - dmap->counts[dmap->qhead], 1, + audio_devs[dev]->d->output_block (dev, dmap->raw_buf_phys + + dmap->qhead * dmap->fragment_size, + dmap->counts[dmap->qhead], 1, !(audio_devs[dev]->flags & DMA_AUTOMODE)); - if (audio_devs[dev]->trigger) - audio_devs[dev]->trigger (dev, + if (audio_devs[dev]->d->trigger) + audio_devs[dev]->d->trigger (dev, audio_devs[dev]->enable_bits * audio_devs[dev]->go); } dmap->flags |= DMA_ACTIVE; @@ -1408,6 +1521,7 @@ } dmap->qlen--; + this_fragment = dmap->qhead; dmap->qhead = (dmap->qhead + 1) % dmap->nbufs; dmap->flags &= ~DMA_ACTIVE; @@ -1415,8 +1529,11 @@ { dmap->underrun_count++; - if (!(dmap->flags & DMA_CLEAN) && - (audio_devs[dev]->flags & DMA_SYNCING || dmap->underrun_count > 5 || dmap->flags & DMA_EMPTY)) + if ((!(dmap->flags & DMA_CLEAN) && + (audio_devs[dev]->dmap_out->flags & DMA_SYNCING || + dmap->underrun_count > 5 || dmap->flags & DMA_EMPTY)) || + audio_devs[dev]->flags & DMA_HARDSTOP) + { dmap->qlen = 0; force_restart (dev, dmap); @@ -1426,7 +1543,7 @@ if (dmap->closing) { polish_buffers (dmap); - audio_devs[dev]->halt_xfer (dev); + audio_devs[dev]->d->halt_xfer (dev); } else { @@ -1444,18 +1561,27 @@ if (dmap->qlen) { + if (dmap->flags & DMA_CLEAN) + { + int p = dmap->fragment_size * this_fragment; + + memset (dmap->raw_buf + p, + dmap->neutral_byte, + dmap->fragment_size); + } + if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) { if (dmap->counts[dmap->qhead] == 0) dmap->counts[dmap->qhead] = dmap->fragment_size; - audio_devs[dev]->output_block (dev, dmap->raw_buf_phys + + audio_devs[dev]->d->output_block (dev, dmap->raw_buf_phys + dmap->qhead * dmap->fragment_size, - dmap->counts[dmap->qhead], 1, + dmap->counts[dmap->qhead], 1, !(audio_devs[dev]->flags & DMA_AUTOMODE)); - if (audio_devs[dev]->trigger) - audio_devs[dev]->trigger (dev, + if (audio_devs[dev]->d->trigger) + audio_devs[dev]->d->trigger (dev, audio_devs[dev]->enable_bits * audio_devs[dev]->go); } dmap->flags |= DMA_ACTIVE; @@ -1464,10 +1590,10 @@ save_flags (flags); cli (); - if ((out_sleep_flag[dev].mode & WK_SLEEP)) + if ((out_sleep_flag[dev].flags & WK_SLEEP)) { { - out_sleep_flag[dev].mode = WK_WAKEUP; + out_sleep_flag[dev].flags = WK_WAKEUP; module_wake_up (&out_sleeper[dev]); }; } @@ -1486,6 +1612,12 @@ sound_dma_intr (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2); #endif + if (dmap->raw_buf == NULL) + { + printk ("Sound: Fatal error. Audio interrupt after freeing buffers.\n"); + return; + } + if (dmap->mapping_flags & DMA_MAP_MAPPED) { dmap->qtail = (dmap->qtail + 1) % dmap->nbufs; @@ -1493,12 +1625,12 @@ if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) { - audio_devs[dev]->start_input (dev, dmap->raw_buf_phys + - dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 1, + audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys + + dmap->qtail * dmap->fragment_size, + dmap->fragment_size, 1, !(audio_devs[dev]->flags & DMA_AUTOMODE)); - if (audio_devs[dev]->trigger) - audio_devs[dev]->trigger (dev, + if (audio_devs[dev]->d->trigger) + audio_devs[dev]->d->trigger (dev, audio_devs[dev]->enable_bits * audio_devs[dev]->go); } @@ -1513,10 +1645,10 @@ { /* Force restart on next read */ if ((audio_devs[dev]->flags & DMA_DUPLEX) && - audio_devs[dev]->halt_input) - audio_devs[dev]->halt_input (dev); + audio_devs[dev]->d->halt_input) + audio_devs[dev]->d->halt_input (dev); else - audio_devs[dev]->halt_xfer (dev); + audio_devs[dev]->d->halt_xfer (dev); dmap->flags &= ~DMA_ACTIVE; if (audio_devs[dev]->flags & DMA_AUTOMODE) @@ -1536,12 +1668,12 @@ if (!(audio_devs[dev]->flags & DMA_AUTOMODE)) { - audio_devs[dev]->start_input (dev, dmap->raw_buf_phys + - dmap->qtail * dmap->fragment_size, - dmap->fragment_size, 1, + audio_devs[dev]->d->start_input (dev, dmap->raw_buf_phys + + dmap->qtail * dmap->fragment_size, + dmap->fragment_size, 1, !(audio_devs[dev]->flags & DMA_AUTOMODE)); - if (audio_devs[dev]->trigger) - audio_devs[dev]->trigger (dev, + if (audio_devs[dev]->d->trigger) + audio_devs[dev]->d->trigger (dev, audio_devs[dev]->enable_bits * audio_devs[dev]->go); } @@ -1549,10 +1681,10 @@ save_flags (flags); cli (); - if ((in_sleep_flag[dev].mode & WK_SLEEP)) + if ((in_sleep_flag[dev].flags & WK_SLEEP)) { { - in_sleep_flag[dev].mode = WK_WAKEUP; + in_sleep_flag[dev].flags = WK_WAKEUP; module_wake_up (&in_sleeper[dev]); }; } @@ -1562,39 +1694,21 @@ int DMAbuf_open_dma (int dev) { +/* + * NOTE! This routine opens only the primary DMA channel (output). + */ + int chan = audio_devs[dev]->dmachan1; int err; unsigned long flags; if ((err = open_dmap (dev, OPEN_READWRITE, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1)) < 0) { - return -EBUSY; + return -(EBUSY); } dma_init_buffers (dev, audio_devs[dev]->dmap_out); audio_devs[dev]->dmap_out->flags |= DMA_ALLOC_DONE; audio_devs[dev]->dmap_out->fragment_size = audio_devs[dev]->buffsize; - /* reorganize_buffers (dev, audio_devs[dev]->dmap_out); */ - - if (audio_devs[dev]->flags & DMA_DUPLEX) - { - if ((err = open_dmap (dev, OPEN_READWRITE, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2)) < 0) - { - printk ("Unable to grab DMA%d for the audio driver\n", - audio_devs[dev]->dmachan2); - close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1); - return -EBUSY; - } - dma_init_buffers (dev, audio_devs[dev]->dmap_in); - audio_devs[dev]->dmap_in->flags |= DMA_ALLOC_DONE; - audio_devs[dev]->dmap_in->fragment_size = audio_devs[dev]->buffsize; - /* reorganize_buffers (dev, audio_devs[dev]->dmap_in); */ - } - else - { - audio_devs[dev]->dmap_in = audio_devs[dev]->dmap_out; - audio_devs[dev]->dmachan2 = audio_devs[dev]->dmachan1; - } - save_flags (flags); cli (); @@ -1610,10 +1724,6 @@ { DMAbuf_reset_dma (dev); close_dmap (dev, audio_devs[dev]->dmap_out, audio_devs[dev]->dmachan1); - - if (audio_devs[dev]->flags & DMA_DUPLEX) - close_dmap (dev, audio_devs[dev]->dmap_in, audio_devs[dev]->dmachan2); - } void @@ -1640,7 +1750,7 @@ save_flags (flags); cli (); - in_sleep_flag[dev].mode = WK_SLEEP; + in_sleep_flag[dev].flags = WK_SLEEP; module_select_wait (&in_sleeper[dev], wait); restore_flags (flags); return 0; @@ -1667,7 +1777,7 @@ save_flags (flags); cli (); - in_sleep_flag[dev].mode = WK_SLEEP; + in_sleep_flag[dev].flags = WK_SLEEP; module_select_wait (&in_sleeper[dev], wait); restore_flags (flags); return 0; @@ -1686,7 +1796,7 @@ save_flags (flags); cli (); - out_sleep_flag[dev].mode = WK_SLEEP; + out_sleep_flag[dev].flags = WK_SLEEP; module_select_wait (&out_sleeper[dev], wait); restore_flags (flags); return 0; @@ -1707,7 +1817,7 @@ save_flags (flags); cli (); - out_sleep_flag[dev].mode = WK_SLEEP; + out_sleep_flag[dev].flags = WK_SLEEP; module_select_wait (&out_sleeper[dev], wait); restore_flags (flags); return 0; @@ -1731,7 +1841,7 @@ int DMAbuf_open (int dev, int mode) { - return -ENXIO; + return -(ENXIO); } int @@ -1743,49 +1853,48 @@ int DMAbuf_getwrbuffer (int dev, char **buf, int *size, int dontblock) { - return -EIO; + return -(EIO); } int DMAbuf_getrdbuffer (int dev, char **buf, int *len, int dontblock) { - return -EIO; + return -(EIO); } int DMAbuf_rmchars (int dev, int buff_no, int c) { - return -EIO; + return -(EIO); } int DMAbuf_start_output (int dev, int buff_no, int l) { - return -EIO; + return -(EIO); } int DMAbuf_ioctl (int dev, unsigned int cmd, caddr_t arg, int local) { - return -EIO; + return -(EIO); } -long -DMAbuf_init (long mem_start) +void +DMAbuf_init (void) { - return mem_start; } int DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode) { - return -EIO; + return -(EIO); } int DMAbuf_open_dma (int dev) { - return -ENXIO; + return -(ENXIO); } void diff -ur --new-file old/linux/drivers/sound/dmasound.c new/linux/drivers/sound/dmasound.c --- old/linux/drivers/sound/dmasound.c Mon May 20 06:54:28 1996 +++ new/linux/drivers/sound/dmasound.c Sat Jul 6 10:31:43 1996 @@ -57,7 +57,7 @@ to cut data only at sample sizes, buffer size is now a kernel runtime option, implemented fsync() & several minor improvements - ++Guenther: useful hints and bugfixes, cross-checked it for + ++Guenther: useful hints and bug fixes, cross-checked it for Falcons 1996/3/9 ++geert: support added for Amiga, A-law, 16-bit little endian. @@ -99,7 +99,7 @@ #ifdef CONFIG_AMIGA /* - * The minimum period for audio depends on htotal (for OCS/ECS/AGA) + * The minimum period for audio depends on total (for OCS/ECS/AGA) * (Imported from arch/m68k/amiga/amisound.c) */ @@ -307,7 +307,7 @@ #ifdef HAS_14BIT_TABLES -/* 14 bit mu-law (lsb) */ +/* 14 bit mu-law (LSB) */ static char alaw2dma14l[] = { 33, 33, 33, 33, 33, 33, 33, 33, @@ -344,7 +344,7 @@ 14, 12, 10, 8, 6, 4, 2, 0 }; -/* 14 bit A-law (lsb) */ +/* 14 bit A-law (LSB) */ static char alaw2dma14l[] = { 32, 32, 32, 32, 32, 32, 32, 32, diff -ur --new-file old/linux/drivers/sound/finetune.h new/linux/drivers/sound/finetune.h --- old/linux/drivers/sound/finetune.h Sun Mar 24 21:49:41 1996 +++ new/linux/drivers/sound/finetune.h Sun Jun 30 10:43:37 1996 @@ -1,26 +1,10 @@ #ifdef SEQUENCER_C /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ diff -ur --new-file old/linux/drivers/sound/gus_card.c new/linux/drivers/sound/gus_card.c --- old/linux/drivers/sound/gus_card.c Sun Mar 24 21:49:59 1996 +++ new/linux/drivers/sound/gus_card.c Sun Jun 30 10:43:56 1996 @@ -4,27 +4,11 @@ * Detection routine for the Gravis Ultrasound. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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 @@ -45,8 +29,8 @@ int *gus_osp; -long -attach_gus_card (long mem_start, struct address_info *hw_config) +void +attach_gus_card (struct address_info *hw_config) { int io_addr; @@ -57,7 +41,7 @@ * Try first the default */ { - mem_start = gus_wave_init (mem_start, hw_config); + gus_wave_init (hw_config); request_region (hw_config->io_base, 16, "GUS"); request_region (hw_config->io_base + 0x100, 12, "GUS"); /* 0x10c-> is MAX */ @@ -68,9 +52,9 @@ if (sound_alloc_dma (hw_config->dma2, "GUS(2)")) printk ("gus_card.c: Can't allocate DMA channel2\n"); #ifdef CONFIG_MIDI - mem_start = gus_midi_init (mem_start); + gus_midi_init (); #endif - return mem_start; + return; } #ifndef EXCLUDE_GUS_IODETECT @@ -88,7 +72,7 @@ hw_config->io_base = io_addr; printk (" WARNING! GUS found at %x, config was %x ", io_addr, hw_config->io_base); - mem_start = gus_wave_init (mem_start, hw_config); + gus_wave_init (hw_config); request_region (io_addr, 16, "GUS"); request_region (io_addr + 0x100, 12, "GUS"); /* 0x10c-> is MAX */ if (sound_alloc_dma (hw_config->dma, "GUS")) @@ -97,16 +81,13 @@ if (sound_alloc_dma (hw_config->dma2, "GUS")) printk ("gus_card.c: Can't allocate DMA channel2\n"); #ifdef CONFIG_MIDI - mem_start = gus_midi_init (mem_start); + gus_midi_init (); #endif - return mem_start; + return; } #endif - return mem_start; /* - * Not detected - */ } int @@ -242,8 +223,8 @@ return ad1848_detect (hw_config->io_base, NULL, hw_config->osp); } -long -attach_gus_db16 (long mem_start, struct address_info *hw_config) +void +attach_gus_db16 (struct address_info *hw_config) { #ifdef CONFIG_GUS gus_pcm_volume = 100; @@ -255,7 +236,6 @@ hw_config->dma, hw_config->dma, 0, hw_config->osp); - return mem_start; } void diff -ur --new-file old/linux/drivers/sound/gus_midi.c new/linux/drivers/sound/gus_midi.c --- old/linux/drivers/sound/gus_midi.c Sun Mar 24 21:49:59 1996 +++ new/linux/drivers/sound/gus_midi.c Sun Jun 30 10:43:56 1996 @@ -4,27 +4,11 @@ * The low level driver for the GUS Midi Interface. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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 @@ -64,7 +48,7 @@ if (midi_busy) { printk ("GUS: Midi busy\n"); - return -EBUSY; + return -(EBUSY); } outb (MIDI_RESET, u_MidiControl); @@ -196,7 +180,7 @@ static int gus_midi_ioctl (int dev, unsigned cmd, caddr_t arg) { - return -EINVAL; + return -(EINVAL); } static void @@ -249,20 +233,20 @@ NULL }; -long -gus_midi_init (long mem_start) +void +gus_midi_init (void) { if (num_midis >= MAX_MIDI_DEV) { printk ("Sound: Too many midi devices detected\n"); - return mem_start; + return; } outb (MIDI_RESET, u_MidiControl); std_midi_synth.midi_dev = my_dev = num_midis; midi_devs[num_midis++] = &gus_midi_operations; - return mem_start; + return; } void diff -ur --new-file old/linux/drivers/sound/gus_vol.c new/linux/drivers/sound/gus_vol.c --- old/linux/drivers/sound/gus_vol.c Sun Mar 24 21:50:00 1996 +++ new/linux/drivers/sound/gus_vol.c Sat Jul 6 10:31:42 1996 @@ -2,27 +2,11 @@ * gus_vol.c - Compute volume for GUS. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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 @@ -97,7 +81,7 @@ return ((15 << 8) | 255); /* - * Convert to gus's logarithmic form with 4 bit exponent i and 8 bit + * Convert to GUS's logarithmic form with 4 bit exponent i and 8 bit * mantissa m. */ n = x; diff -ur --new-file old/linux/drivers/sound/gus_wave.c new/linux/drivers/sound/gus_wave.c --- old/linux/drivers/sound/gus_wave.c Mon May 6 11:26:12 1996 +++ new/linux/drivers/sound/gus_wave.c Sun Aug 18 09:46:49 1996 @@ -4,31 +4,17 @@ * Driver for the Gravis UltraSound wave table synth. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) + * Version 2 (June 1991). See the "COPYING" file distributed with this software + * for more info. */ #include +#define GUSPNP_AUTODETECT + #include "sound_config.h" #include #include "gus_hw.h" @@ -113,9 +99,9 @@ #define GUS_DEV_PCM_DONE 2 /* PCM device, transfer done */ #define GUS_DEV_PCM_CONTINUE 3 /* PCM device, transfer done ch. 1/2 */ -static int gus_sampling_speed; -static int gus_sampling_channels; -static int gus_sampling_bits; +static int gus_audio_speed; +static int gus_audio_channels; +static int gus_audio_bits; static wait_handle *dram_sleeper = NULL; static volatile struct snd_wait dram_sleep_flag = @@ -337,8 +323,27 @@ return ((hi << 8) & 0xff00) | lo; } +unsigned short +gus_look16 (int reg) +{ /* Reads from an indirect register (16 bit). No additional offset. */ + unsigned long flags; + unsigned char hi, lo; + + save_flags (flags); + cli (); + + outb (reg, u_Command); + + lo = inb (u_DataLo); + hi = inb (u_DataHi); + + restore_flags (flags); + + return ((hi << 8) & 0xff00) | lo; +} + void -gus_write_addr (int reg, unsigned long address, int is16bit) +gus_write_addr (int reg, unsigned long address, int frac, int is16bit) { /* Writes an 24 bit memory address */ unsigned long hold_address; unsigned long flags; @@ -358,11 +363,13 @@ } gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff)); - gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff)); - /* Could writing twice fix problems with GUS_VOICE_POS() ? Let's try... */ + gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff) + + (frac << 5)); + /* Could writing twice fix problems with GUS_VOICE_POS() ? Lets try... */ gus_delay (); gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff)); - gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff)); + gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff) + + (frac << 5)); restore_flags (flags); } @@ -488,7 +495,7 @@ if (voices[voice].volume_irq_mode == VMODE_START_NOTE) voices[voice].offset_pending = position; else - gus_write_addr (0x0a, sample_ptrs[sample_no] + position, + gus_write_addr (0x0a, sample_ptrs[sample_no] + position, 0, samples[sample_no].mode & WAVE_16_BITS); } @@ -502,7 +509,7 @@ gus_select_voice (voice); gus_voice_volume (0); gus_voice_off (); - gus_write_addr (0x0a, 0, 0); /* Set current position to 0 */ + gus_write_addr (0x0a, 0, 0, 0); /* Set current position to 0 */ gus_write8 (0x00, 0x03); /* Voice off */ gus_write8 (0x0d, 0x03); /* Ramping off */ voice_alloc->map[voice] = 0; @@ -687,14 +694,6 @@ gus_voice_init (i); /* Turn voice off */ gus_voice_init2 (i); } - - inb (u_Status); /* Touch the status register */ - - gus_look8 (0x41); /* Clear any pending DMA IRQs */ - gus_look8 (0x49); /* Clear any pending sample IRQs */ - - gus_read8 (0x0f); /* Clear pending IRQs */ - } static void @@ -838,14 +837,194 @@ gus_select_voice (0); /* This disables writes to IRQ/DMA reg */ - gusintr (0, NULL, NULL); /* Serve pending interrupts */ + gusintr (gus_irq, NULL, NULL); /* Serve pending interrupts */ + + inb (u_Status); /* Touch the status register */ + + gus_look8 (0x41); /* Clear any pending DMA IRQs */ + gus_look8 (0x49); /* Clear any pending sample IRQs */ + + gus_read8 (0x0f); /* Clear pending IRQs */ + restore_flags (flags); } +static void +pnp_mem_init (void) +{ +#include "iwmem.h" +#define CHUNK_SIZE (256*1024) +#define BANK_SIZE (4*1024*1024) +#define CHUNKS_PER_BANK (BANK_SIZE/CHUNK_SIZE) + + int bank, chunk, addr, total = 0; + int bank_sizes[4]; + int i, j, bits = -1, nbanks = 0; + +/* + * This routine determines what kind of RAM is installed in each of the four + * SIMM banks and configures the DRAM address decode logic accordingly. + */ + +/* + * Place the chip into enhanced mode + */ + gus_write8 (0x19, gus_read8 (0x19) | 0x01); + gus_write8 (0x53, gus_look8 (0x53) & ~0x02); /* Select DRAM I/O access */ + +/* + * Set memory configuration to 4 DRAM banks of 4M in each (16M total). + */ + + gus_write16 (0x52, (gus_look16 (0x52) & 0xfff0) | 0x000c); + +/* + * Perform the DRAM size detection for each bank individually. + */ + for (bank = 0; bank < 4; bank++) + { + int size = 0; + + addr = bank * BANK_SIZE; + + /* Clean check points of each chunk */ + for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++) + { + gus_poke (addr + chunk * CHUNK_SIZE + 0L, 0x00); + gus_poke (addr + chunk * CHUNK_SIZE + 1L, 0x00); + } + + /* Write a value to each chunk point and verify the result */ + for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++) + { + gus_poke (addr + chunk * CHUNK_SIZE + 0L, 0x55); + gus_poke (addr + chunk * CHUNK_SIZE + 1L, 0xAA); + + if (gus_peek (addr + chunk * CHUNK_SIZE + 0L) == 0x55 && + gus_peek (addr + chunk * CHUNK_SIZE + 1L) == 0xAA) + { /* OK. There is RAM. Now check for possible shadows */ + int ok = 1, chunk2; + + for (chunk2 = 0; ok && chunk2 < chunk; chunk2++) + if (gus_peek (addr + chunk2 * CHUNK_SIZE + 0L) || + gus_peek (addr + chunk2 * CHUNK_SIZE + 1L)) + ok = 0; /* Addressing wraps */ + + if (ok) + size = (chunk + 1) * CHUNK_SIZE; + } + gus_poke (addr + chunk * CHUNK_SIZE + 0L, 0x00); + gus_poke (addr + chunk * CHUNK_SIZE + 1L, 0x00); + } + + bank_sizes[bank] = size; + if (size) + nbanks = bank + 1; + DDB (printk ("Interwave: Bank %d, size=%dk\n", bank, size / 1024)); + } + + if (nbanks == 0) /* No RAM - Give up */ + { + printk ("Sound: An Interwave audio chip detected but no DRAM\n"); + printk ("Sound: Unable to work with this card.\n"); + gus_write8 (0x19, gus_read8 (0x19) & ~0x01); + return; + } +/* + * Now we know how much DRAM there is in each bank. The next step is + * to find a DRAM size encoding (0 to 12) which is best for the combination + * we have. + * + * First try if any of the possible alternatives matches exactly the amount + * of memory we have. + */ + + for (i = 0; bits == -1 && i < 13; i++) + { + bits = i; + + for (j = 0; bits != -1 && j < 4; j++) + if (mem_decode[i][j] != bank_sizes[j]) + bits = -1; /* No hit */ + } + +/* + * If necessary, try to find a combination where other than the last + * bank matches our configuration and the last bank is left oversized. + * In this way we don't leave holes in the middle of memory. + */ + if (bits == -1) /* No luck yet */ + for (i = 0; bits == -1 && i < 13; i++) + { + bits = i; + + for (j = 0; bits != -1 && j < nbanks - 1; j++) + if (mem_decode[i][j] != bank_sizes[j]) + bits = -1; /* No hit */ + if (mem_decode[i][nbanks - 1] < bank_sizes[nbanks - 1]) + bits = -1; /* The last bank is too small */ + } + +/* + * The last resort is to search for a combination where the last bank is + * smaller than the actual SIMM. This leaves some memory in the last bank + * unused but doesn't leave holes in the DRAM address space. + */ + if (bits == -1) /* No luck yet */ + { + for (i = 0; bits == -1 && i < 13; i++) + { + bits = i; + + for (j = 0; bits != -1 && j < nbanks - 1; j++) + if (mem_decode[i][j] != bank_sizes[j]) + bits = -1; /* No hit */ + } + + if (bits != -1) + { + printk ("Interwave: Can't use all installed RAM.\n"); + printk ("Interwave: Try reordering SIMMS.\n"); + } + } + + if (bits == -1) + { + printk ("Interwave: Can't find working DRAM encoding.\n"); + printk ("Interwave: Defaulting to 256k. Try reordering SIMMS.\n"); + bits = 0; + } + + DDB (printk ("Interwave: Selecting DRAM addressing mode %d\n", bits)); + + for (bank = 0; bank < 4; bank++) + { + DDB (printk (" Bank %d, mem=%dk (limit %dk)\n", + bank, bank_sizes[bank] / 1024, + mem_decode[bits][bank] / 1024)); + + if (bank_sizes[bank] > mem_decode[bits][bank]) + total += mem_decode[bits][bank]; + else + total += bank_sizes[bank]; + } + + DDB (printk ("Total %dk of DRAM (enhanced mode)\n", total / 1024)); +/* + * Set the memory addressing mode. + */ + gus_write16 (0x52, (gus_look16 (0x52) & 0xfff0) | bits); + +/* + * Return the chip back to GUS compatible mode. + */ + gus_write8 (0x19, gus_read8 (0x19) & ~0x01); +} + int gus_wave_detect (int baseaddr) { - unsigned long i; + unsigned long i, max_mem = 1024L; unsigned long loc; gus_base = baseaddr; @@ -858,6 +1037,9 @@ gus_delay (); gus_delay (); + if (gus_pnp_flag) + pnp_mem_init (); + /* See if there is first block there.... */ gus_poke (0L, 0xaa); if (gus_peek (0L) != 0xaa) @@ -865,7 +1047,7 @@ /* Now zero it out so that I can check for mirroring .. */ gus_poke (0L, 0x00); - for (i = 1L; i < 1024L; i++) + for (i = 1L; i < max_mem; i++) { int n, failed; @@ -901,7 +1083,7 @@ { case SNDCTL_SYNTH_INFO: gus_info.nr_voices = nr_voices; - memcpy_tofs ((&((char *) arg)[0]), &gus_info, sizeof (gus_info)); + memcpy_tofs (&((char *) arg)[0], &gus_info, sizeof (gus_info)); return 0; break; @@ -918,7 +1100,7 @@ return gus_mem_size - free_mem_ptr - 32; default: - return -EINVAL; + return -(EINVAL); } } @@ -928,10 +1110,10 @@ int sample_no; if (instr_no < 0 || instr_no > MAX_PATCH) - return -EINVAL; + return -(EINVAL); if (voice < 0 || voice > 31) - return -EINVAL; + return -(EINVAL); if (voices[voice].volume_irq_mode == VMODE_START_NOTE) { @@ -945,14 +1127,14 @@ if (sample_no == NOT_SAMPLE) { printk ("GUS: Undefined patch %d for voice %d\n", instr_no, voice); - return -EINVAL; /* Patch not defined */ + return -(EINVAL); /* Patch not defined */ } if (sample_ptrs[sample_no] == -1) /* Sample not loaded */ { printk ("GUS: Sample #%d not loaded for patch %d (voice %d)\n", sample_no, instr_no, voice); - return -EINVAL; + return -(EINVAL); } sample_map[voice] = sample_no; @@ -1206,7 +1388,7 @@ if (voice < 0 || voice > 31) { printk ("GUS: Invalid voice\n"); - return -EINVAL; + return -(EINVAL); } if (note_num == 255) @@ -1224,12 +1406,12 @@ if ((patch = patch_map[voice]) == -1) { - return -EINVAL; + return -(EINVAL); } if ((samplep = patch_table[patch]) == NOT_SAMPLE) { - return -EINVAL; + return -(EINVAL); } note_freq = note_to_freq (note_num); @@ -1343,10 +1525,10 @@ if (samples[sample].mode & WAVE_LOOP_BACK) gus_write_addr (0x0a, sample_ptrs[sample] + samples[sample].len - - voices[voice].offset_pending, is16bits); /* start=end */ + voices[voice].offset_pending, 0, is16bits); /* start=end */ else gus_write_addr (0x0a, sample_ptrs[sample] + voices[voice].offset_pending, - is16bits); /* Sample start=begin */ + 0, is16bits); /* Sample start=begin */ if (samples[sample].mode & WAVE_LOOPING) { @@ -1359,13 +1541,16 @@ { gus_write_addr (0x0a, sample_ptrs[sample] + samples[sample].loop_end - - voices[voice].offset_pending, is16bits); + voices[voice].offset_pending, + (samples[sample].fractions >> 4) & 0x0f, is16bits); mode |= 0x40; } gus_write_addr (0x02, sample_ptrs[sample] + samples[sample].loop_start, + samples[sample].fractions & 0x0f, is16bits); /* Loop start location */ gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].loop_end, + (samples[sample].fractions >> 4) & 0x0f, is16bits); /* Loop end location */ } else @@ -1374,8 +1559,9 @@ voices[voice].loop_irq_mode = LMODE_FINISH; /* Ramp down at the end */ voices[voice].loop_irq_parm = 1; gus_write_addr (0x02, sample_ptrs[sample], - is16bits); /* Loop start location */ + 0, is16bits); /* Loop start location */ gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].len - 1, + (samples[sample].fractions >> 4) & 0x0f, is16bits); /* Loop end location */ } gus_voice_freq (freq); @@ -1435,7 +1621,7 @@ gus_select_voice (voice); /* Reselect the voice (just to be sure) */ } - if ((mode & 0x01) || (int) ((gus_read16 (0x09) >> 4) < 2065)) + if ((mode & 0x01) || (int) ((gus_read16 (0x09) >> 4) < (unsigned) 2065)) { ret_val = guswave_start_note2 (dev, voice, note_num, volume); } @@ -1474,24 +1660,26 @@ int err; if (gus_busy) - return -EBUSY; + return -(EBUSY); - gus_initialize (); voice_alloc->timestamp = 0; if ((err = DMAbuf_open_dma (gus_devnum)) < 0) { - printk ("GUS: Loading samples without DMA\n"); + /* printk ("GUS: Loading samples without DMA\n"); */ gus_no_dma = 1; /* Upload samples using PIO */ } else gus_no_dma = 0; - dram_sleep_flag.mode = WK_NONE; + dram_sleep_flag.flags = WK_NONE; gus_busy = 1; active_device = GUS_DEV_WAVE; + gusintr (gus_irq, NULL, NULL); /* Serve pending interrupts */ + gus_initialize (); gus_reset (); + gusintr (gus_irq, NULL, NULL); /* Serve pending interrupts */ return 0; } @@ -1522,13 +1710,13 @@ if (format != GUS_PATCH) { printk ("GUS Error: Invalid patch format (key) 0x%x\n", format); - return -EINVAL; + return -(EINVAL); } if (count < sizeof_patch) { printk ("GUS Error: Patch header too short\n"); - return -EINVAL; + return -(EINVAL); } count -= sizeof_patch; @@ -1536,7 +1724,7 @@ if (free_sample >= MAX_SAMPLE) { printk ("GUS: Sample table full\n"); - return -ENOSPC; + return -(ENOSPC); } /* @@ -1544,14 +1732,14 @@ * been transferred already. */ - memcpy_fromfs (&((char *) &patch)[offs], &((addr)[offs]), sizeof_patch - offs); + memcpy_fromfs (&((char *) &patch)[offs], &(addr)[offs], sizeof_patch - offs); instr = patch.instr_no; if (instr < 0 || instr > MAX_PATCH) { printk ("GUS: Invalid patch number %d\n", instr); - return -EINVAL; + return -(EINVAL); } if (count < patch.len) @@ -1564,7 +1752,7 @@ if (patch.len <= 0 || patch.len > gus_mem_size) { printk ("GUS: Invalid sample length %d\n", (int) patch.len); - return -EINVAL; + return -(EINVAL); } if (patch.mode & WAVE_LOOPING) @@ -1572,13 +1760,13 @@ if (patch.loop_start < 0 || patch.loop_start >= patch.len) { printk ("GUS: Invalid loop start\n"); - return -EINVAL; + return -(EINVAL); } if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len) { printk ("GUS: Invalid loop end\n"); - return -EINVAL; + return -(EINVAL); } } @@ -1594,24 +1782,24 @@ if (patch.len >= GUS_BANK_SIZE) { printk ("GUS: Sample (16 bit) too long %d\n", (int) patch.len); - return -ENOSPC; + return -(ENOSPC); } if ((free_mem_ptr / GUS_BANK_SIZE) != ((free_mem_ptr + patch.len) / GUS_BANK_SIZE)) { - unsigned long tmp_mem = /* Aling to 256K */ + unsigned long tmp_mem = /* Align to 256K */ ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE; if ((tmp_mem + patch.len) > gus_mem_size) - return -ENOSPC; + return -(ENOSPC); free_mem_ptr = tmp_mem; /* This leaves unusable memory */ } } if ((free_mem_ptr + patch.len) > gus_mem_size) - return -ENOSPC; + return -(ENOSPC); sample_ptrs[free_sample] = free_mem_ptr; @@ -1622,6 +1810,11 @@ if (patch.mode & WAVE_ENVELOPES) patch.mode &= ~WAVE_TREMOLO; + if (!(patch.mode & WAVE_FRACTIONS)) + { + patch.fractions = 0; + } + memcpy ((char *) &samples[free_sample], &patch, sizeof_patch); /* @@ -1641,7 +1834,6 @@ while (left) /* Not completely transferred yet */ { - /* blk_sz = audio_devs[gus_devnum]->buffsize; */ blk_sz = audio_devs[gus_devnum]->dmap_out->bytes_in_use; if (blk_sz > left) blk_sz = left; @@ -1658,7 +1850,7 @@ blk_sz = blk_end - target; } - if (gus_pnp_flag || gus_no_dma) + if (gus_no_dma) { /* * For some reason the DMA is not possible. We have to use PIO. @@ -1683,11 +1875,17 @@ unsigned char dma_command; unsigned long flags; + if (audio_devs[gus_devnum]->dmap_out->raw_buf == NULL) + { + printk ("GUS: DMA buffer == NULL\n"); + return -(EINVAL); + } + /* * OK, move now. First in and then out. */ - memcpy_fromfs (audio_devs[gus_devnum]->dmap_out->raw_buf, &((addr)[sizeof_patch + src_offs]), blk_sz); + memcpy_fromfs (audio_devs[gus_devnum]->dmap_out->raw_buf, &(addr)[sizeof_patch + src_offs], blk_sz); save_flags (flags); cli (); @@ -1734,22 +1932,22 @@ { - unsigned long tl; + unsigned long tlimit; if (HZ) - current_set_timeout (tl = jiffies + (HZ)); + current_set_timeout (tlimit = jiffies + (HZ)); else - tl = (unsigned long) -1; - dram_sleep_flag.mode = WK_SLEEP; + tlimit = (unsigned long) -1; + dram_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&dram_sleeper); - if (!(dram_sleep_flag.mode & WK_WAKEUP)) + if (!(dram_sleep_flag.flags & WK_WAKEUP)) { - if (jiffies >= tl) - dram_sleep_flag.mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + dram_sleep_flag.flags |= WK_TIMEOUT; } - dram_sleep_flag.mode &= ~WK_SLEEP; + dram_sleep_flag.flags &= ~WK_SLEEP; }; - if ((dram_sleep_flag.mode & WK_TIMEOUT)) + if ((dram_sleep_flag.flags & WK_TIMEOUT)) printk ("GUS: DMA Transfer timed out\n"); restore_flags (flags); } @@ -1935,11 +2133,11 @@ } static int -gus_sampling_set_speed (int speed) +gus_audio_set_speed (int speed) { if (speed <= 0) - speed = gus_sampling_speed; + speed = gus_audio_speed; if (speed < 4000) speed = 4000; @@ -1947,36 +2145,37 @@ if (speed > 44100) speed = 44100; - gus_sampling_speed = speed; + gus_audio_speed = speed; if (only_read_access) { /* Compute nearest valid recording speed and return it */ - speed = (9878400 / (gus_sampling_speed + 2)) / 16; + /* speed = (9878400 / (gus_audio_speed + 2)) / 16; */ + speed = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16; speed = (9878400 / (speed * 16)) - 2; } return speed; } static int -gus_sampling_set_channels (int channels) +gus_audio_set_channels (int channels) { if (!channels) - return gus_sampling_channels; + return gus_audio_channels; if (channels > 2) channels = 2; if (channels < 1) channels = 1; - gus_sampling_channels = channels; + gus_audio_channels = channels; return channels; } static int -gus_sampling_set_bits (int bits) +gus_audio_set_bits (int bits) { if (!bits) - return gus_sampling_bits; + return gus_audio_bits; if (bits != 8 && bits != 16) bits = 8; @@ -1984,70 +2183,70 @@ if (only_8_bits) bits = 8; - gus_sampling_bits = bits; + gus_audio_bits = bits; return bits; } static int -gus_sampling_ioctl (int dev, unsigned int cmd, caddr_t arg, int local) +gus_audio_ioctl (int dev, unsigned int cmd, caddr_t arg, int local) { switch (cmd) { case SOUND_PCM_WRITE_RATE: if (local) - return gus_sampling_set_speed ((int) arg); - return snd_ioctl_return ((int *) arg, gus_sampling_set_speed (get_fs_long ((long *) arg))); + return gus_audio_set_speed ((int) arg); + return snd_ioctl_return ((int *) arg, gus_audio_set_speed (get_user ((int *) arg))); break; case SOUND_PCM_READ_RATE: if (local) - return gus_sampling_speed; - return snd_ioctl_return ((int *) arg, gus_sampling_speed); + return gus_audio_speed; + return snd_ioctl_return ((int *) arg, gus_audio_speed); break; case SNDCTL_DSP_STEREO: if (local) - return gus_sampling_set_channels ((int) arg + 1) - 1; - return snd_ioctl_return ((int *) arg, gus_sampling_set_channels (get_fs_long ((long *) arg) + 1) - 1); + return gus_audio_set_channels ((int) arg + 1) - 1; + return snd_ioctl_return ((int *) arg, gus_audio_set_channels (get_user ((int *) arg) + 1) - 1); break; case SOUND_PCM_WRITE_CHANNELS: if (local) - return gus_sampling_set_channels ((int) arg); - return snd_ioctl_return ((int *) arg, gus_sampling_set_channels (get_fs_long ((long *) arg))); + return gus_audio_set_channels ((int) arg); + return snd_ioctl_return ((int *) arg, gus_audio_set_channels (get_user ((int *) arg))); break; case SOUND_PCM_READ_CHANNELS: if (local) - return gus_sampling_channels; - return snd_ioctl_return ((int *) arg, gus_sampling_channels); + return gus_audio_channels; + return snd_ioctl_return ((int *) arg, gus_audio_channels); break; case SNDCTL_DSP_SETFMT: if (local) - return gus_sampling_set_bits ((int) arg); - return snd_ioctl_return ((int *) arg, gus_sampling_set_bits (get_fs_long ((long *) arg))); + return gus_audio_set_bits ((int) arg); + return snd_ioctl_return ((int *) arg, gus_audio_set_bits (get_user ((int *) arg))); break; case SOUND_PCM_READ_BITS: if (local) - return gus_sampling_bits; - return snd_ioctl_return ((int *) arg, gus_sampling_bits); + return gus_audio_bits; + return snd_ioctl_return ((int *) arg, gus_audio_bits); case SOUND_PCM_WRITE_FILTER: /* NOT POSSIBLE */ - return snd_ioctl_return ((int *) arg, -EINVAL); + return snd_ioctl_return ((int *) arg, -(EINVAL)); break; case SOUND_PCM_READ_FILTER: - return snd_ioctl_return ((int *) arg, -EINVAL); + return snd_ioctl_return ((int *) arg, -(EINVAL)); break; } - return -EINVAL; + return -(EINVAL); } static void -gus_sampling_reset (int dev) +gus_audio_reset (int dev) { if (recording_active) { @@ -2057,11 +2256,16 @@ } static int -gus_sampling_open (int dev, int mode) +gus_audio_open (int dev, int mode) { if (gus_busy) - return -EBUSY; + return -(EBUSY); + if (gus_pnp_flag && mode & OPEN_READ) + { + printk ("Sound: This audio device doesn't have recording capability\n"); + return -(EIO); + } gus_initialize (); gus_busy = 1; @@ -2090,7 +2294,7 @@ } static void -gus_sampling_close (int dev) +gus_audio_close (int dev) { gus_reset (); gus_busy = 0; @@ -2107,13 +2311,13 @@ } static void -gus_sampling_update_volume (void) +gus_audio_update_volume (void) { unsigned long flags; int voice; if (pcm_active && pcm_opened) - for (voice = 0; voice < gus_sampling_channels; voice++) + for (voice = 0; voice < gus_audio_channels; voice++) { save_flags (flags); cli (); @@ -2129,7 +2333,7 @@ play_next_pcm_block (void) { unsigned long flags; - int speed = gus_sampling_speed; + int speed = gus_audio_speed; int this_one, is16bits, chn; unsigned long dram_loc; unsigned char mode[2], ramp_mode[2]; @@ -2139,7 +2343,7 @@ this_one = pcm_head; - for (chn = 0; chn < gus_sampling_channels; chn++) + for (chn = 0; chn < gus_audio_channels; chn++) { mode[chn] = 0x00; ramp_mode[chn] = 0x03; /* Ramping and rollover off */ @@ -2150,7 +2354,7 @@ voices[chn].loop_irq_mode = LMODE_PCM; } - if (gus_sampling_bits != 8) + if (gus_audio_bits != 8) { is16bits = 1; mode[chn] |= 0x04; /* 16 bit data */ @@ -2177,7 +2381,7 @@ gus_select_voice (chn); gus_voice_freq (speed); - if (gus_sampling_channels == 1) + if (gus_audio_channels == 1) gus_voice_balance (7); /* mono */ else if (chn == 0) gus_voice_balance (0); /* left */ @@ -2198,17 +2402,17 @@ gus_voice_volume (1530 + (25 * gus_pcm_volume)); gus_ramp_range (65, 1530 + (25 * gus_pcm_volume)); - gus_write_addr (0x0a, dram_loc, is16bits); /* Starting position */ - gus_write_addr (0x02, chn * pcm_banksize, is16bits); /* Loop start */ + gus_write_addr (0x0a, dram_loc, 0, is16bits); /* Starting position */ + gus_write_addr (0x02, chn * pcm_banksize, 0, is16bits); /* Loop start */ if (chn != 0) gus_write_addr (0x04, pcm_banksize + (pcm_bsize * pcm_nblk) - 1, - is16bits); /* Loop end location */ + 0, is16bits); /* Loop end location */ } if (chn == 0) gus_write_addr (0x04, dram_loc + pcm_datasize[this_one] - 1, - is16bits); /* Loop end location */ + 0, is16bits); /* Loop end location */ else mode[chn] |= 0x08; /* Enable looping */ @@ -2227,7 +2431,7 @@ else { gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], - is16bits); /* Loop end location */ + 0, is16bits); /* Loop end location */ mode[chn] &= ~0x08; /* Disable looping */ } } @@ -2235,7 +2439,7 @@ restore_flags (flags); } - for (chn = 0; chn < gus_sampling_channels; chn++) + for (chn = 0; chn < gus_audio_channels; chn++) { save_flags (flags); cli (); @@ -2269,7 +2473,7 @@ save_flags (flags); cli (); - count = total_count / gus_sampling_channels; + count = total_count / gus_audio_channels; if (chn == 0) { @@ -2302,7 +2506,7 @@ dma_command = 0x21; /* IRQ enable, DMA start */ - if (gus_sampling_bits != 8) + if (gus_audio_bits != 8) dma_command |= 0x40; /* 16 bit _DATA_ */ else dma_command |= 0x80; /* Invert MSB */ @@ -2310,9 +2514,9 @@ if (audio_devs[dev]->dmachan1 > 3) dma_command |= 0x04; /* 16 bit DMA channel */ - gus_write8 (0x41, dma_command); /* Kickstart */ + gus_write8 (0x41, dma_command); /* Kick start */ - if (chn == (gus_sampling_channels - 1)) /* Last channel */ + if (chn == (gus_audio_channels - 1)) /* Last channel */ { /* * Last (right or mono) channel data @@ -2337,8 +2541,8 @@ } static void -gus_sampling_output_block (int dev, unsigned long buf, int total_count, - int intrflag, int restart_dma) +gus_audio_output_block (int dev, unsigned long buf, int total_count, + int intrflag, int restart_dma) { pcm_current_buf = buf; pcm_current_count = total_count; @@ -2348,8 +2552,8 @@ } static void -gus_sampling_start_input (int dev, unsigned long buf, int count, - int intrflag, int restart_dma) +gus_audio_start_input (int dev, unsigned long buf, int count, + int intrflag, int restart_dma) { unsigned long flags; unsigned char mode; @@ -2363,7 +2567,7 @@ if (audio_devs[dev]->dmachan2 > 3) mode |= 0x04; /* 16 bit DMA channel */ - if (gus_sampling_channels > 1) + if (gus_audio_channels > 1) mode |= 0x02; /* Stereo */ mode |= 0x01; /* DMA enable */ @@ -2373,37 +2577,37 @@ } static int -gus_sampling_prepare_for_input (int dev, int bsize, int bcount) +gus_audio_prepare_for_input (int dev, int bsize, int bcount) { unsigned int rate; - rate = (9878400 / (gus_sampling_speed + 2)) / 16; + rate = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16; gus_write8 (0x48, rate & 0xff); /* Set sampling rate */ - if (gus_sampling_bits != 8) + if (gus_audio_bits != 8) { printk ("GUS Error: 16 bit recording not supported\n"); - return -EINVAL; + return -(EINVAL); } return 0; } static int -gus_sampling_prepare_for_output (int dev, int bsize, int bcount) +gus_audio_prepare_for_output (int dev, int bsize, int bcount) { int i; long mem_ptr, mem_size; mem_ptr = 0; - mem_size = gus_mem_size / gus_sampling_channels; + mem_size = gus_mem_size / gus_audio_channels; if (mem_size > (256 * 1024)) mem_size = 256 * 1024; - pcm_bsize = bsize / gus_sampling_channels; + pcm_bsize = bsize / gus_audio_channels; pcm_head = pcm_tail = pcm_qlen = 0; pcm_nblk = MAX_PCM_BUFFERS; @@ -2415,7 +2619,7 @@ pcm_banksize = pcm_nblk * pcm_bsize; - if (gus_sampling_bits != 8 && pcm_banksize == (256 * 1024)) + if (gus_audio_bits != 8 && pcm_banksize == (256 * 1024)) pcm_nblk--; return 0; @@ -2431,11 +2635,11 @@ gus_copy_from_user (int dev, char *localbuf, int localoffs, const char *userbuf, int useroffs, int len) { - if (gus_sampling_channels == 1) + if (gus_audio_channels == 1) { - memcpy_fromfs (&localbuf[localoffs], &((userbuf)[useroffs]), len); + memcpy_fromfs (&localbuf[localoffs], &(userbuf)[useroffs], len); } - else if (gus_sampling_bits == 8) + else if (gus_audio_bits == 8) { int in_left = useroffs; int in_right = useroffs + 1; @@ -2444,7 +2648,7 @@ len /= 2; localoffs /= 2; - out_left = &localbuf[localoffs]; + out_left = localbuf + localoffs; out_right = out_left + pcm_bsize; for (i = 0; i < len; i++) @@ -2465,7 +2669,7 @@ len /= 4; localoffs /= 4; - out_left = (short *) &localbuf[localoffs]; + out_left = ((short *) localbuf) + localoffs; out_right = out_left + (pcm_bsize / 2); for (i = 0; i < len; i++) @@ -2478,23 +2682,28 @@ } } -static struct audio_operations gus_sampling_operations = +static struct audio_driver gus_audio_driver = +{ + gus_audio_open, + gus_audio_close, + gus_audio_output_block, + gus_audio_start_input, + gus_audio_ioctl, + gus_audio_prepare_for_input, + gus_audio_prepare_for_output, + gus_audio_reset, + gus_audio_reset, + gus_local_qlen, + gus_copy_from_user +}; + +static struct audio_operations gus_audio_operations = { "Gravis UltraSound", NEEDS_RESTART, AFMT_U8 | AFMT_S16_LE, NULL, - gus_sampling_open, - gus_sampling_close, - gus_sampling_output_block, - gus_sampling_start_input, - gus_sampling_ioctl, - gus_sampling_prepare_for_input, - gus_sampling_prepare_for_output, - gus_sampling_reset, - gus_sampling_reset, - gus_local_qlen, - gus_copy_from_user + &gus_audio_driver }; static void @@ -2506,9 +2715,9 @@ guswave_set_instr (dev, voice, info->pgm_num); voices[voice].expression_vol = - info->controllers[CTL_EXPRESSION]; /* Just msb */ + info->controllers[CTL_EXPRESSION]; /* Just MSB */ voices[voice].main_vol = - (info->controllers[CTL_MAIN_VOLUME] * 100) / 128; + (info->controllers[CTL_MAIN_VOLUME] * 100) / (unsigned) 128; voices[voice].panning = (info->controllers[CTL_PAN] * 2) - 128; voices[voice].bender = info->bender_value; @@ -2589,7 +2798,7 @@ struct patch_info *pat; if (ptr < 0 || ptr >= free_sample) - return -EINVAL; + return -(EINVAL); memcpy (rec->data.data8, (char *) &samples[ptr], sizeof (struct patch_info)); @@ -2609,12 +2818,12 @@ struct patch_info *pat; if (ptr < 0 || ptr >= free_sample) - return -EINVAL; + return -(EINVAL); pat = (struct patch_info *) rec->data.data8; if (pat->len > samples[ptr].len) /* Cannot expand sample */ - return -EINVAL; + return -(EINVAL); pat->key = samples[ptr].key; /* Ensure the link is correct */ @@ -2634,10 +2843,10 @@ int l = rec->parm3; if (sample < 0 || sample >= free_sample) - return -EINVAL; + return -(EINVAL); if (offs < 0 || offs >= samples[sample].len) - return -EINVAL; /* Invalid offset */ + return -(EINVAL); /* Invalid offset */ n = samples[sample].len - offs; /* Num of bytes left */ @@ -2648,12 +2857,12 @@ l = sizeof (rec->data.data8); if (l <= 0) - return -EINVAL; /* + return -(EINVAL); /* * Was there a bug? */ offs += sample_ptrs[sample]; /* - * Begin offset + offset to DRAM + * Begin offsets + offset to DRAM */ for (n = 0; n < l; n++) @@ -2675,10 +2884,10 @@ int l = rec->parm3; if (sample < 0 || sample >= free_sample) - return -EINVAL; + return -(EINVAL); if (offs < 0 || offs >= samples[sample].len) - return -EINVAL; /* + return -(EINVAL); /* * Invalid offset */ @@ -2693,12 +2902,12 @@ l = sizeof (rec->data.data8); if (l <= 0) - return -EINVAL; /* + return -(EINVAL); /* * Was there a bug? */ offs += sample_ptrs[sample]; /* - * Begin offset + offset to DRAM + * Begin offsets + offset to DRAM */ for (n = 0; n < l; n++) @@ -2711,7 +2920,7 @@ break; default: - return -EINVAL; + return -(EINVAL); } } @@ -2837,7 +3046,7 @@ switch (cmd & 0xff) { case SOUND_MIXER_RECSRC: - gus_recmask = get_fs_long ((long *) arg) & MIX_DEVS; + gus_recmask = get_user ((int *) arg) & MIX_DEVS; if (!(gus_recmask & (SOUND_MASK_MIC | SOUND_MASK_LINE))) gus_recmask = SOUND_MASK_MIC; /* Note! Input volumes are updated during next open for recording */ @@ -2846,7 +3055,7 @@ case SOUND_MIXER_MIC: { - int vol = get_fs_long ((long *) arg) & 0xff; + int vol = get_user ((int *) arg) & 0xff; if (vol < 0) vol = 0; @@ -2860,7 +3069,7 @@ case SOUND_MIXER_LINE: { - int vol = get_fs_long ((long *) arg) & 0xff; + int vol = get_user ((int *) arg) & 0xff; if (vol < 0) vol = 0; @@ -2873,12 +3082,12 @@ break; case SOUND_MIXER_PCM: - gus_pcm_volume = get_fs_long ((long *) arg) & 0xff; + gus_pcm_volume = get_user ((int *) arg) & 0xff; if (gus_pcm_volume < 0) gus_pcm_volume = 0; if (gus_pcm_volume > 100) gus_pcm_volume = 100; - gus_sampling_update_volume (); + gus_audio_update_volume (); return snd_ioctl_return ((int *) arg, gus_pcm_volume | (gus_pcm_volume << 8)); break; @@ -2886,7 +3095,7 @@ { int voice; - gus_wave_volume = get_fs_long ((long *) arg) & 0xff; + gus_wave_volume = get_user ((int *) arg) & 0xff; if (gus_wave_volume < 0) gus_wave_volume = 0; @@ -2902,7 +3111,7 @@ break; default: - return -EINVAL; + return -(EINVAL); } else switch (cmd & 0xff) /* @@ -2947,21 +3156,22 @@ break; default: - return -EINVAL; + return -(EINVAL); } } else - return -EINVAL; + return -(EINVAL); } static struct mixer_operations gus_mixer_operations = { + "GUS", "Gravis Ultrasound", gus_default_mixer_ioctl }; -static long -gus_default_mixer_init (long mem_start) +static void +gus_default_mixer_init (void) { if (num_mixers < MAX_MIXER_DEV) /* * Don't install if there is another @@ -2979,11 +3189,10 @@ mix_image |= 0x04; /* All channels enabled */ outb (mix_image, u_Mixer); } - return mem_start; } -long -gus_wave_init (long mem_start, struct address_info *hw_config) +void +gus_wave_init (struct address_info *hw_config) { unsigned long flags; unsigned char val; @@ -2996,13 +3205,13 @@ if (irq < 0 || irq > 15) { printk ("ERROR! Invalid IRQ#%d. GUS Disabled", irq); - return mem_start; + return; } if (dma < 0 || dma > 7 || dma == 4) { printk ("ERROR! Invalid DMA#%d. GUS Disabled", dma); - return mem_start; + return; } gus_irq = irq; @@ -3018,18 +3227,36 @@ * Versions < 3.6 don't have the digital ASIC. Try to probe it first. */ +#ifdef GUSPNP_AUTODETECT + val = gus_look8 (0x5b); /* Version number register */ + gus_write8 (0x5b, ~val); /* Invert all bits */ + + if ((gus_look8 (0x5b) & 0xf0) == (val & 0xf0)) /* No change */ + if ((gus_look8 (0x5b) & 0x0f) == ((~val) & 0x0f)) /* Change */ + { + DDB (printk ("Interwave chip version %d detected\n", (val & 0xf0) >> 4)); + gus_pnp_flag = 1; + } + else + { + DDB (printk ("Not an Interwave chip\n")); + gus_pnp_flag = 0; + } + gus_write8 (0x5b, val); /* Restore all bits */ +#endif + save_flags (flags); cli (); outb (0x20, gus_base + 0x0f); val = inb (gus_base + 0x0f); restore_flags (flags); -#ifndef GUSPNP_NO_AUTODETECT - gus_pnp_flag = (val == 1); -#endif - if (gus_pnp_flag || (val != 0xff && (val & 0x06))) /* Should be 0x02?? */ { + int ad_flags = 0; + + if (gus_pnp_flag) + ad_flags = 0x12345678; /* Interwave "magic" */ /* * It has the digital ASIC so the card is at least v3.4. * Next try to detect the true model. @@ -3082,13 +3309,17 @@ outb (max_config, gus_base + 0x106); /* UltraMax control */ } - if (ad1848_detect (gus_base + 0x10c, NULL, hw_config->osp)) + if (ad1848_detect (gus_base + 0x10c, &ad_flags, hw_config->osp)) { + char *name = "GUS MAX"; gus_mic_vol = gus_line_vol = gus_pcm_volume = 100; gus_wave_volume = 90; have_gus_max = 1; - ad1848_init ("GUS MAX", gus_base + 0x10c, + if (hw_config->name) + name = hw_config->name; + + ad1848_init (name, gus_base + 0x10c, -irq, gus_dma2, /* Playback DMA */ gus_dma, /* Capture DMA */ @@ -3123,13 +3354,13 @@ sprintf (gus_info.name, "Gravis UltraSound %s (%dk)", model_num, (int) gus_mem_size / 1024); - samples = (struct patch_info *) (sound_mem_blocks[sound_num_blocks] = kmalloc ((MAX_SAMPLE + 1) * sizeof (*samples), GFP_KERNEL)); - if (sound_num_blocks < 1024) - sound_num_blocks++;; + samples = (struct patch_info *) (sound_mem_blocks[sound_nblocks] = vmalloc ((MAX_SAMPLE + 1) * sizeof (*samples))); + if (sound_nblocks < 1024) + sound_nblocks++;; if (samples == NULL) { - printk ("GUS Error: Can't allocate memory for instrument tables\n"); - return mem_start; + printk ("GUS Error: Cant allocate memory for instrument tables\n"); + return; } conf_printf (gus_info.name, hw_config); @@ -3151,10 +3382,13 @@ if (num_audiodevs < MAX_AUDIO_DEV) { - audio_devs[gus_devnum = num_audiodevs++] = &gus_sampling_operations; + audio_devs[gus_devnum = num_audiodevs++] = &gus_audio_operations; audio_devs[gus_devnum]->dmachan1 = dma; audio_devs[gus_devnum]->dmachan2 = dma2; audio_devs[gus_devnum]->buffsize = DSP_BUFFSIZE; + audio_devs[gus_devnum]->min_fragment = 9; + audio_devs[gus_devnum]->mixer_dev = num_mixers; /* Next mixer# */ + audio_devs[gus_devnum]->flags |= DMA_HARDSTOP; if (dma2 != dma && dma2 != -1) audio_devs[gus_devnum]->flags |= DMA_DUPLEX; } @@ -3171,12 +3405,14 @@ gus_mic_vol = gus_line_vol = gus_pcm_volume = 100; gus_wave_volume = 90; request_region (u_MixSelect, 1, "GUS mixer"); - return ics2101_mixer_init (mem_start); + ics2101_mixer_init (); + return; case CS4231: /* Initialized elsewhere (ad1848.c) */ default: - return gus_default_mixer_init (mem_start); + gus_default_mixer_init (); + return; } } @@ -3412,9 +3648,9 @@ switch (active_device) { case GUS_DEV_WAVE: - if ((dram_sleep_flag.mode & WK_SLEEP)) + if ((dram_sleep_flag.flags & WK_SLEEP)) { - dram_sleep_flag.mode = WK_WAKEUP; + dram_sleep_flag.flags = WK_WAKEUP; module_wake_up (&dram_sleeper); }; break; diff -ur --new-file old/linux/drivers/sound/ics2101.c new/linux/drivers/sound/ics2101.c --- old/linux/drivers/sound/ics2101.c Sun Mar 24 21:50:04 1996 +++ new/linux/drivers/sound/ics2101.c Sun Aug 18 09:46:49 1996 @@ -4,27 +4,11 @@ * Driver for the ICS2101 mixer of GUS v3.7. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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 @@ -144,27 +128,27 @@ break; case SOUND_MIXER_MIC: - return snd_ioctl_return ((int *) arg, set_volumes (DEV_MIC, get_fs_long ((long *) arg))); + return snd_ioctl_return ((int *) arg, set_volumes (DEV_MIC, get_user ((int *) arg))); break; case SOUND_MIXER_CD: - return snd_ioctl_return ((int *) arg, set_volumes (DEV_CD, get_fs_long ((long *) arg))); + return snd_ioctl_return ((int *) arg, set_volumes (DEV_CD, get_user ((int *) arg))); break; case SOUND_MIXER_LINE: - return snd_ioctl_return ((int *) arg, set_volumes (DEV_LINE, get_fs_long ((long *) arg))); + return snd_ioctl_return ((int *) arg, set_volumes (DEV_LINE, get_user ((int *) arg))); break; case SOUND_MIXER_SYNTH: - return snd_ioctl_return ((int *) arg, set_volumes (DEV_GF1, get_fs_long ((long *) arg))); + return snd_ioctl_return ((int *) arg, set_volumes (DEV_GF1, get_user ((int *) arg))); break; case SOUND_MIXER_VOLUME: - return snd_ioctl_return ((int *) arg, set_volumes (DEV_VOL, get_fs_long ((long *) arg))); + return snd_ioctl_return ((int *) arg, set_volumes (DEV_VOL, get_user ((int *) arg))); break; default: - return -EINVAL; + return -(EINVAL); } else switch (cmd & 0xff) /* @@ -213,21 +197,22 @@ break; default: - return -EINVAL; + return -(EINVAL); } } - return -EINVAL; + return -(EINVAL); } static struct mixer_operations ics2101_mixer_operations = { + "ICS2101", "ICS2101 Multimedia Mixer", ics2101_mixer_ioctl }; -long -ics2101_mixer_init (long mem_start) +void +ics2101_mixer_init (void) { int i; @@ -256,7 +241,6 @@ set_volumes (DEV_UNUSED, 0x0000); } - return mem_start; } #endif diff -ur --new-file old/linux/drivers/sound/iwmem.h new/linux/drivers/sound/iwmem.h --- old/linux/drivers/sound/iwmem.h Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/sound/iwmem.h Sun Jun 30 11:30:15 1996 @@ -0,0 +1,33 @@ +/* + * sound/iwmem.c + * + * DRAM size encoding table for AMD Interwave chip. + */ +/* + * Copyright (C) by Hannu Savolainen 1993-1996 + * + * USS/Lite 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. + */ + + +#define K 1024 +#define M (1024*K) +static int mem_decode[][4] = +{ +/* Bank0 Bank1 Bank2 Bank3 Encoding bits */ + {256*K, 0, 0, 0}, /* 0 */ + {256*K, 256*K, 0, 0}, /* 1 */ + {256*K, 256*K, 256*K, 256*K}, /* 2 */ + {256*K, 1*M, 0, 0}, /* 3 */ + {256*K, 1*M, 1*M, 1*M}, /* 4 */ + {256*K, 256*K, 1*M, 0}, /* 5 */ + {256*K, 256*K, 1*M, 1*M}, /* 6 */ + {1*M, 0, 0, 0}, /* 7 */ + {1*M, 1*M, 0, 0}, /* 8 */ + {1*M, 1*M, 1*M, 1*M}, /* 9 */ + {4*M, 0, 0, 0}, /* 10 */ + {4*M, 4*M, 0, 0}, /* 11 */ + {4*M, 4*M, 4*M, 4*M} /* 12 */ +}; diff -ur --new-file old/linux/drivers/sound/lowlevel/Config.tmpl new/linux/drivers/sound/lowlevel/Config.tmpl --- old/linux/drivers/sound/lowlevel/Config.tmpl Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/sound/lowlevel/Config.tmpl Thu May 16 10:05:56 1996 @@ -0,0 +1,5 @@ +bool 'Additional low level drivers' CONFIG_LOWLEVEL_SOUND + +if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then + bool 'ACI mixer (miroPCM12)' CONFIG_ACI_MIXER +fi diff -ur --new-file old/linux/drivers/sound/lowlevel/Makefile new/linux/drivers/sound/lowlevel/Makefile --- old/linux/drivers/sound/lowlevel/Makefile Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/sound/lowlevel/Makefile Thu May 16 10:05:57 1996 @@ -0,0 +1,19 @@ +all: lowlevel.o + +OBJS = init.o + +ifdef CONFIG_LOWLEVEL_SOUND +ifdef CONFIG_ACI_MIXER +OBJS := $(OBJS) aci.o +endif +endif + +lowlevel.o: $(OBJS) + ld -r -o lowlevel.o $(OBJS) + +clean: + rm -f core x y z *~ *.o + +ifdef HOSTCC +include $(TOPDIR)/Rules.make +endif diff -ur --new-file old/linux/drivers/sound/lowlevel/README new/linux/drivers/sound/lowlevel/README --- old/linux/drivers/sound/lowlevel/README Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/sound/lowlevel/README Thu May 16 10:09:13 1996 @@ -0,0 +1,13 @@ +Additional low level sound drivers for Linux +-------------------------------------------- + +This directory contains additional low level sound drivers which +are not part of USS/Lite (UNIX Sound System). These drivers are +maintained by their authors. + +If you like to write a low level sound driver, please contact +Hannu Savolainen (hannu@voxware.pp.fi) for more info. + +The following low level drivers are included: + +- ACI MIXER for miroPCM12 by Markus Kuhn. See aci.readme for more info. diff -ur --new-file old/linux/drivers/sound/lowlevel/aci.c new/linux/drivers/sound/lowlevel/aci.c --- old/linux/drivers/sound/lowlevel/aci.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/sound/lowlevel/aci.c Sat Jul 6 10:31:42 1996 @@ -0,0 +1,590 @@ +/* + * Audio Command Interface (ACI) driver (sound/aci.c) + * + * ACI is a protocol used to communicate with the microcontroller on + * some sound cards produced by miro, e.g. the miroSOUND PCM12 and + * PCM20. The ACI has been developed for miro by Norberto Pellicci + * . Special thanks to both him and miro for + * providing the ACI specification. + * + * The main function of the ACI is to control the mixer and to get a + * product identification. On the PCM20, ACI also controls the radio + * tuner on this card, however this is not yet supported in this + * software. + * + * This Voxware ACI driver currently only supports the ACI functions + * on the miroSOUND PCM12 card. Support for miro soundcards with + * additional ACI functions can easily be added later. + * + * Revision history: + * + * 1995-11-10 Markus Kuhn + * First version written. + * 1995-12-31 Markus Kuhn + * Second revision, general code cleanup. + * 1996-05-16 Hannu Savolainen + * Integrated with other parts of the driver. + * 1996-05-28 Markus Kuhn + * Initialize CS4231A mixer, make ACI first mixer, + * use new private mixer API for solo mode. + */ + +/* + * Some driver specific information and features: + * + * This mixer driver identifies itself to applications as "ACI" in + * mixer_info.id as retrieved by ioctl(fd, SOUND_MIXER_INFO, &mixer_info). + * + * Proprietary mixer features that go beyond the standard USS mixer + * interface are: + * + * Full duplex solo configuration: + * + * int solo_mode; + * ioctl(fd, SOUND_MIXER_PRIVATE1, &solo_mode); + * + * solo_mode = 0: deactivate solo mode (default) + * solo_mode > 0: activate solo mode + * With activated solo mode, the PCM input can not any + * longer hear the signals produced by the PCM output. + * Activating solo mode is important in duplex mode in order + * to avoid feedback distortions. + * solo_mode < 0: do not change solo mode (just retrieve the status) + * + * When the ioctl() returns 0, solo_mode contains the previous + * status (0 = deactivated, 1 = activated). If solo mode is not + * implemented on this card, ioctl() returns -1 and sets errno to + * EINVAL. + * + */ + +#include "../sound_config.h" +#ifdef CONFIG_ACI_MIXER + +#undef DEBUG /* if defined, produce a verbose report via syslog */ + +int aci_port = 0x354; /* as determined by bit 4 in the OPTi 929 MC4 register */ +unsigned char aci_idcode[2] = {0, 0}; /* manufacturer and product ID */ +unsigned char aci_version = 0; /* ACI firmware version */ +int aci_solo; /* status bit of the card that can't be * + * checked with ACI versions prior to 0xb0 */ + +static int aci_present = 0; + +#define COMMAND_REGISTER (aci_port) +#define STATUS_REGISTER (aci_port + 1) +#define BUSY_REGISTER (aci_port + 2) + +/* + * Wait until the ACI microcontroller has set the READYFLAG in the + * Busy/IRQ Source Register to 0. This is required to avoid + * overrunning the soundcard microcontroller. We do a busy wait here, + * because the microcontroller is not supposed to signal a busy + * condition for more than a few clock cycles. In case of a time-out, + * this function returns -1. + * + * This busy wait code normally requires less than 15 loops and + * practically always less than 100 loops on my i486/DX2 66 MHz. + * + * Warning: Waiting on the general status flag after reseting the MUTE + * function can take a VERY long time, because the PCM12 does some kind + * of fade-in effect. For this reason, access to the MUTE function has + * not been implemented at all. + */ + +static int busy_wait(void) +{ + long timeout; + + for (timeout = 0; timeout < 10000000L; timeout++) + if ((inb_p(BUSY_REGISTER) & 1) == 0) + return 0; + +#ifdef DEBUG + printk("ACI: READYFLAG timed out.\n"); +#endif + + return -1; +} + + +/* + * Read the GENERAL STATUS register. + */ + +static int read_general_status(void) +{ + unsigned long flags; + int status; + + save_flags(flags); + cli(); + if (busy_wait()) { restore_flags(flags); return -1; } + status = (unsigned) inb_p(STATUS_REGISTER); + restore_flags(flags); + return status; +} + + +/* + * The four ACI command types (implied, write, read and indexed) can + * be sent to the microcontroller using the following four functions. + * If a problem occurred, they return -1. + */ + +static int implied_cmd(unsigned char opcode) +{ + unsigned long flags; + +#ifdef DEBUG + printk("ACI: implied_cmd(0x%02x)\n", opcode); +#endif + + save_flags(flags); + cli(); + + if (read_general_status() < 0 || busy_wait()) { + restore_flags(flags); + return -1; + } + outb_p(opcode, COMMAND_REGISTER); + + restore_flags(flags); + return 0; +} + + +static int write_cmd(unsigned char opcode, unsigned char parameter) +{ + unsigned long flags; + int status; + +#ifdef DEBUG + printk("ACI: write_cmd(0x%02x, 0x%02x)\n", opcode, parameter); +#endif + + save_flags(flags); + cli(); + + if (read_general_status() < 0 || busy_wait()) { + restore_flags(flags); + return -1; + } + outb_p(opcode, COMMAND_REGISTER); + if (busy_wait()) { restore_flags(flags); return -1; } + outb_p(parameter, COMMAND_REGISTER); + + if ((status = read_general_status()) < 0) { + restore_flags(flags); + return -1; + } + /* polarity of the INVALID flag depends on ACI version */ + if ((aci_version < 0xb0 && (status & 0x40) != 0) || + (aci_version >= 0xb0 && (status & 0x40) == 0)) { + restore_flags(flags); + printk("ACI: invalid write command 0x%02x, 0x%02x.\n", + opcode, parameter); + return -1; + } + + restore_flags(flags); + return 0; +} + + +static int read_cmd(unsigned char opcode, int length, unsigned char *parameter) +{ + unsigned long flags; + int i = 0; + + save_flags(flags); + cli(); + + if (read_general_status() < 0) { restore_flags(flags); return -1; } + while (i < length) { + if (busy_wait()) { restore_flags(flags); return -1; } + outb_p(opcode, COMMAND_REGISTER); + if (busy_wait()) { restore_flags(flags); return -1; } + parameter[i++] = inb_p(STATUS_REGISTER); +#ifdef DEBUG + if (i == 1) + printk("ACI: read_cmd(0x%02x, %d) = 0x%02x\n", opcode, length, + parameter[i-1]); + else + printk("ACI: read_cmd cont.: 0x%02x\n", parameter[i-1]); +#endif + } + + restore_flags(flags); + return 0; +} + + +static int indexed_cmd(unsigned char opcode, unsigned char index, + unsigned char *parameter) +{ + unsigned long flags; + + save_flags(flags); + cli(); + + if (read_general_status() < 0 || busy_wait()) { + restore_flags(flags); + return -1; + } + outb_p(opcode, COMMAND_REGISTER); + if (busy_wait()) { restore_flags(flags); return -1; } + outb_p(index, COMMAND_REGISTER); + if (busy_wait()) { restore_flags(flags); return -1; } + *parameter = inb_p(STATUS_REGISTER); +#ifdef DEBUG + printk("ACI: indexed_cmd(0x%02x, 0x%02x) = 0x%02x\n", opcode, index, + *parameter); +#endif + + restore_flags(flags); + return 0; +} + + +/* + * The following macro SCALE can be used to scale one integer volume + * value into another one using only integer arithmetic. If the input + * value x is in the range 0 <= x <= xmax, then the result will be in + * the range 0 <= SCALE(xmax,ymax,x) <= ymax. + * + * This macro has for all xmax, ymax > 0 and all 0 <= x <= xmax the + * following nice properties: + * + * - SCALE(xmax,ymax,xmax) = ymax + * - SCALE(xmax,ymax,0) = 0 + * - SCALE(xmax,ymax,SCALE(ymax,xmax,SCALE(xmax,ymax,x))) = SCALE(xmax,ymax,x) + * + * In addition, the rounding error is minimal and nicely distributed. + * The proofs are left as an exercise to the reader. + */ + +#define SCALE(xmax,ymax,x) (((x)*(ymax)+(xmax)/2)/(xmax)) + + +static int getvolume(caddr_t arg, + unsigned char left_index, unsigned char right_index) +{ + int vol; + unsigned char buf; + + /* left channel */ + if (indexed_cmd(0xf0, left_index, &buf)) return -EIO; + vol = SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0); + /* right channel */ + if (indexed_cmd(0xf0, right_index, &buf)) return -EIO; + vol |= SCALE(0x20, 100, buf < 0x20 ? 0x20-buf : 0) << 8; + + return snd_ioctl_return((int *) arg, vol); +} + + +static int setvolume(caddr_t arg, + unsigned char left_index, unsigned char right_index) +{ + int vol, ret; + unsigned param; + + param = get_user((int *) arg); + /* left channel */ + vol = param & 0xff; + if (vol > 100) vol = 100; + vol = SCALE(100, 0x20, vol); + if (write_cmd(left_index, 0x20 - vol)) return -EIO; + ret = SCALE(0x20, 100, vol); + /* right channel */ + vol = (param >> 8) & 0xff; + if (vol > 100) vol = 100; + vol = SCALE(100, 0x20, vol); + if (write_cmd(right_index, 0x20 - vol)) return -EIO; + ret |= SCALE(0x20, 100, vol) << 8; + + return snd_ioctl_return((int *) arg, ret); +} + + +static int +aci_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) +{ + int status, vol; + unsigned char buf; + + /* handle solo mode control */ + if (cmd == SOUND_MIXER_PRIVATE1) { + if (get_user((int *) arg) >= 0) { + aci_solo = !!get_user((int *) arg); + if (write_cmd(0xd2, aci_solo)) return -EIO; + } else if (aci_version >= 0xb0) { + if ((status = read_general_status()) < 0) return -EIO; + return snd_ioctl_return ((int *) arg, (status & 0x20) == 0); + } + return snd_ioctl_return((int *) arg, aci_solo); + } + + if (((cmd >> 8) & 0xff) == 'M') { + if (cmd & IOC_IN) + /* read and write */ + switch (cmd & 0xff) { + case SOUND_MIXER_VOLUME: + return setvolume(arg, 0x01, 0x00); + case SOUND_MIXER_CD: + return setvolume(arg, 0x3c, 0x34); + case SOUND_MIXER_MIC: + return setvolume(arg, 0x38, 0x30); + case SOUND_MIXER_LINE: + return setvolume(arg, 0x39, 0x31); + case SOUND_MIXER_SYNTH: + return setvolume(arg, 0x3b, 0x33); + case SOUND_MIXER_PCM: + return setvolume(arg, 0x3a, 0x32); + case SOUND_MIXER_LINE1: /* AUX1 */ + return setvolume(arg, 0x3d, 0x35); + case SOUND_MIXER_LINE2: /* AUX2 */ + return setvolume(arg, 0x3e, 0x36); + case SOUND_MIXER_IGAIN: /* MIC pre-amp */ + vol = get_user((int *) arg) & 0xff; + if (vol > 100) vol = 100; + vol = SCALE(100, 3, vol); + if (write_cmd(0x03, vol)) return -EIO; + vol = SCALE(3, 100, vol); + return snd_ioctl_return((int *) arg, vol | (vol << 8)); + case SOUND_MIXER_RECSRC: + return snd_ioctl_return ((int *) arg, 0); + break; + default: + return -EINVAL; + } + else + /* only read */ + switch (cmd & 0xff) { + case SOUND_MIXER_DEVMASK: + return snd_ioctl_return ((int *) arg, + SOUND_MASK_VOLUME | SOUND_MASK_CD | + SOUND_MASK_MIC | SOUND_MASK_LINE | + SOUND_MASK_SYNTH | SOUND_MASK_PCM | +#if 0 + SOUND_MASK_IGAIN | +#endif + SOUND_MASK_LINE1 | SOUND_MASK_LINE2); + break; + case SOUND_MIXER_STEREODEVS: + return snd_ioctl_return ((int *) arg, + SOUND_MASK_VOLUME | SOUND_MASK_CD | + SOUND_MASK_MIC | SOUND_MASK_LINE | + SOUND_MASK_SYNTH | SOUND_MASK_PCM | + SOUND_MASK_LINE1 | SOUND_MASK_LINE2); + break; + case SOUND_MIXER_RECMASK: + return snd_ioctl_return ((int *) arg, 0); + break; + case SOUND_MIXER_RECSRC: + return snd_ioctl_return ((int *) arg, 0); + break; + case SOUND_MIXER_CAPS: + return snd_ioctl_return ((int *) arg, 0); + break; + case SOUND_MIXER_VOLUME: + return getvolume(arg, 0x04, 0x03); + case SOUND_MIXER_CD: + return getvolume(arg, 0x0a, 0x09); + case SOUND_MIXER_MIC: + return getvolume(arg, 0x06, 0x05); + case SOUND_MIXER_LINE: + return getvolume(arg, 0x08, 0x07); + case SOUND_MIXER_SYNTH: + return getvolume(arg, 0x0c, 0x0b); + case SOUND_MIXER_PCM: + return getvolume(arg, 0x0e, 0x0d); + case SOUND_MIXER_LINE1: /* AUX1 */ + return getvolume(arg, 0x11, 0x10); + case SOUND_MIXER_LINE2: /* AUX2 */ + return getvolume(arg, 0x13, 0x12); + case SOUND_MIXER_IGAIN: /* MIC pre-amp */ + if (indexed_cmd(0xf0, 0x21, &buf)) return -EIO; + vol = SCALE(3, 100, buf <= 3 ? buf : 3); + vol |= vol << 8; + return snd_ioctl_return((int *) arg, vol); + default: + return -EINVAL; + } + } + + return -EINVAL; +} + + +static struct mixer_operations aci_mixer_operations = +{ + "ACI", + "ACI mixer", + aci_mixer_ioctl, + NULL +}; + +static unsigned char +mad_read (int port) +{ + outb (0xE3, 0xf8f); /* Write MAD16 password */ + return inb (port); /* Read from port */ +} + + +/* + * Check, whether there actually is any ACI port operational and if + * one was found, then initialize the ACI interface, reserve the I/O + * addresses and attach the new mixer to the relevant VoxWare data + * structures. + * + * Returns: 1 ACI mixer detected + * 0 nothing there + * + * There is also an internal mixer in the codec (CS4231A or AD1845), + * that deserves no purpose in an ACI based system which uses an + * external ACI controlled stereo mixer. Make sure that this codec + * mixer has the AUX1 input selected as the recording source, that the + * input gain is set near maximum and that the other channels going + * from the inputs to the codec output are muted. + */ + +int attach_aci(void) +{ + char *boardname = "unknown"; + int volume; + +#define MC4_PORT 0xf90 + + aci_port = + (mad_read(MC4_PORT) & 0x10) ? 0x344 : 0x354; + + if (check_region(aci_port, 3)) { +#ifdef DEBUG + printk("ACI: I/O area 0x%03x-0x%03x already used.\n", + aci_port, aci_port+2); +#endif + return 0; + } + + if (read_cmd(0xf2, 2, aci_idcode)) { +#ifdef DEBUG + printk("ACI: Failed to read idcode.\n"); +#endif + return 0; + } + if (read_cmd(0xf1, 1, &aci_version)) { +#ifdef DEBUG + printk("ACI: Failed to read version.\n"); +#endif + return 0; + } + + if (aci_idcode[0] == 0x6d) { + /* it looks like a miro soundcard */ + switch (aci_idcode[1]) { + case 0x41: + boardname = "PCM1 pro / early PCM12"; + break; + case 0x42: + boardname = "PCM12"; + break; + case 0x43: + boardname = "PCM20"; + break; + default: + boardname = "unknown miro"; + } + } else +#ifndef DEBUG + return 0; +#endif + + printk(" at 0x%03x\n", + aci_version, aci_idcode[0], aci_idcode[1], boardname, aci_port); + + /* initialize ACI mixer */ + implied_cmd(0xff); + aci_solo = 0; + + /* attach the mixer */ + request_region(aci_port, 3, "sound mixer (ACI)"); + if (num_mixers < MAX_MIXER_DEV) { + if (num_mixers > 0 && + !strcmp("MAD16 WSS (CS4231A)", mixer_devs[num_mixers-1]->name)) { + /* + * The previously registered mixer device is the CS4231A which + * has no function on an ACI card. Make the ACI mixer the first + * of the two mixer devices. + */ + mixer_devs[num_mixers] = mixer_devs[num_mixers-1]; + mixer_devs[num_mixers-1] = &aci_mixer_operations; + /* + * Initialize the CS4231A mixer with reasonable values. It is + * unlikely that the user ever will want to change these as all + * channels can be mixed via ACI. + */ + volume = 0x6464; + mixer_devs[num_mixers]-> + ioctl(num_mixers, SOUND_MIXER_WRITE_PCM, (caddr_t) &volume); + volume = 0x6464; + mixer_devs[num_mixers]-> + ioctl(num_mixers, SOUND_MIXER_WRITE_IGAIN, (caddr_t) &volume); + volume = 0; + mixer_devs[num_mixers]-> + ioctl(num_mixers, SOUND_MIXER_WRITE_SPEAKER, (caddr_t) &volume); + volume = 0; + mixer_devs[num_mixers]-> + ioctl(num_mixers, SOUND_MIXER_WRITE_MIC, (caddr_t) &volume); + volume = 0; + mixer_devs[num_mixers]-> + ioctl(num_mixers, SOUND_MIXER_WRITE_IMIX, (caddr_t) &volume); + volume = 0; + mixer_devs[num_mixers]-> + ioctl(num_mixers, SOUND_MIXER_WRITE_LINE1, (caddr_t) &volume); + volume = 0; + mixer_devs[num_mixers]-> + ioctl(num_mixers, SOUND_MIXER_WRITE_LINE2, (caddr_t) &volume); + volume = 0; + mixer_devs[num_mixers]-> + ioctl(num_mixers, SOUND_MIXER_WRITE_LINE3, (caddr_t) &volume); + volume = SOUND_MASK_LINE1; + mixer_devs[num_mixers]-> + ioctl(num_mixers, SOUND_MIXER_WRITE_RECSRC, (caddr_t) &volume); + num_mixers++; + } else + mixer_devs[num_mixers++] = &aci_mixer_operations; + } + + /* Initialize ACI mixer with reasonable power-up values */ + volume = 0x3232; + aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_VOLUME, (caddr_t) &volume); + volume = 0x3232; + aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_SYNTH, (caddr_t) &volume); + volume = 0x3232; + aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_PCM, (caddr_t) &volume); + volume = 0x3232; + aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE, (caddr_t) &volume); + volume = 0x3232; + aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_MIC, (caddr_t) &volume); + volume = 0x3232; + aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_CD, (caddr_t) &volume); + volume = 0x3232; + aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE1, (caddr_t) &volume); + volume = 0x3232; + aci_mixer_ioctl(num_mixers-1, SOUND_MIXER_WRITE_LINE2, (caddr_t) &volume); + + aci_present = 1; + + return 1; +} + +void unload_aci(void) +{ + if (aci_present) + release_region(aci_port, 3); +} + +#endif diff -ur --new-file old/linux/drivers/sound/lowlevel/init.c new/linux/drivers/sound/lowlevel/init.c --- old/linux/drivers/sound/lowlevel/init.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/sound/lowlevel/init.c Tue May 28 16:45:17 1996 @@ -0,0 +1,26 @@ +/* + * lowlevel/init.c - Calls initialization code for configured drivers. + */ + +#include + +#ifdef CONFIG_LOWLEVEL_SOUND +extern int attach_aci(void); +extern void unload_aci(void); + +void +sound_init_lowlevel_drivers(void) +{ +#ifdef CONFIG_ACI_MIXER + attach_aci(); +#endif +} + +void +sound_unload_lowlevel_drivers(void) +{ +#ifdef CONFIG_ACI_MIXER + unload_aci(); +#endif +} +#endif diff -ur --new-file old/linux/drivers/sound/mad16.c new/linux/drivers/sound/mad16.c --- old/linux/drivers/sound/mad16.c Fri Apr 12 08:49:43 1996 +++ new/linux/drivers/sound/mad16.c Wed Aug 14 09:21:03 1996 @@ -1,25 +1,9 @@ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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 @@ -31,7 +15,7 @@ * OPTi 82C928 MAD16 (replaced by C929) * OAK OTI-601D Mozart * OPTi 82C929 MAD16 Pro - * OPTi 82C930 (Not supported yet) + * OPTi 82C930 * * These audio interface chips don't produce sound themselves. They just * connect some other components (OPL-[234] and a WSS compatible codec) @@ -49,7 +33,7 @@ * 0x00 - none * 0x02 - Sony 31A * 0x04 - Mitsumi - * 0x06 - Panasonic (type "LaserMate", not "SoundBlaster") + * 0x06 - Panasonic (type "LaserMate", not "Sound Blaster") * 0x08 - Secondary IDE (address 0x170) * 0x0a - Primary IDE (address 0x1F0) * @@ -77,6 +61,8 @@ #if defined(CONFIG_MAD16) +#include "sb.h" + static int already_initialized = 0; #define C928 1 @@ -91,11 +77,14 @@ * All ports are inactive by default. They can be activated by * writing 0xE2 or 0xE3 to the password register. The password is valid * only until the next I/O read or write. + * + * 82C930 uses 0xE4 as the password and indirect addressing to access + * the config registers. */ #define MC0_PORT 0xf8c /* Dummy port */ -#define MC1_PORT 0xf8d /* SB address, CDROM interface type, joystick */ -#define MC2_PORT 0xf8e /* CDROM address, IRQ, DMA, plus OPL4 bit */ +#define MC1_PORT 0xf8d /* SB address, CD-ROM interface type, joystick */ +#define MC2_PORT 0xf8e /* CD-ROM address, IRQ, DMA, plus OPL4 bit */ #define MC3_PORT 0xf8f #define PASSWD_REG 0xf8f #define MC4_PORT 0xf90 @@ -136,9 +125,18 @@ outb (0xE3, PASSWD_REG); break; + case C930: + /* outb( 0xE4, PASSWD_REG); */ + break; } - tmp = inb (port); + if (board_type == C930) + { + outb (port - MC0_PORT, 0xe0e); /* Write to index reg */ + tmp = inb (0xe0f); /* Read from data reg */ + } + else + tmp = inb (port); restore_flags (flags); return tmp; @@ -163,13 +161,60 @@ outb (0xE3, PASSWD_REG); break; + case C930: + /* outb( 0xE4, PASSWD_REG); */ + break; } - outb ((unsigned char) (value & 0xff), port); + if (board_type == C930) + { + outb (port - MC0_PORT, 0xe0e); /* Write to index reg */ + outb ((unsigned char) (value & 0xff), 0xe0f); + } + else + outb ((unsigned char) (value & 0xff), port); restore_flags (flags); } static int +detect_c930 (void) +{ + unsigned char tmp = mad_read (MC1_PORT); + + if ((tmp & 0x06) != 0x06) + { + DDB (printk ("Wrong C930 signature (%x)\n", tmp)); + /* return 0; */ + } + + mad_write (MC1_PORT, 0); + + if (mad_read (MC1_PORT) != 0x06) + { + DDB (printk ("Wrong C930 signature2 (%x)\n", tmp)); + /* return 0; */ + } + + mad_write (MC1_PORT, tmp); /* Restore bits */ + + mad_write (MC7_PORT, 0); + if ((tmp = mad_read (MC7_PORT)) != 0) + { + DDB (printk ("MC7 not writable (%x)\n", tmp)); + return 0; + } + + mad_write (MC7_PORT, 0xcb); + if ((tmp = mad_read (MC7_PORT)) != 0xcb) + { + DDB (printk ("MC7 not writable2 (%x)\n", tmp)); + return 0; + } + + return 1; +} + +static int detect_mad16 (void) { unsigned char tmp, tmp2; @@ -190,6 +235,8 @@ for (i = 0xf8d; i <= 0xf98; i++) DDB (printk ("Port %0x (init value) = %0x\n", i, mad_read (i))); + if (board_type == C930) + return detect_c930 (); /* * Now check that the gate is closed on first I/O after writing * the password. (This is how a MAD16 compatible card works). @@ -233,7 +280,7 @@ return 0; /* * Check if the IO port returns valid signature. The original MS Sound - * system returns 0x04 while some cards (AudioTriX Pro for example) + * system returns 0x04 while some cards (AudioTrix Pro for example) * return 0x00. */ @@ -275,6 +322,57 @@ return 1; } +static int +init_c930 (struct address_info *hw_config) +{ + unsigned char cfg; + + cfg = (mad_read (MC1_PORT) & ~0x30); + /* mad_write(MC1_PORT, 0); */ + + switch (hw_config->io_base) + { + case 0x530: + cfg |= 0x00; + break; + case 0xe80: + cfg |= 0x10; + break; + case 0xf40: + cfg |= 0x20; + break; + case 0x604: + cfg |= 0x30; + break; + + default: + printk ("MAD16: Invalid codec port %x\n", hw_config->io_base); + return 0; + } + mad_write (MC1_PORT, cfg); + + /* MC2 is CD configuration. Don't touch it. */ + + mad_write (MC3_PORT, 0); /* Disable SB mode IRQ and DMA */ + + mad_write (MC4_PORT, 0x52); /* ??? */ + mad_write (MC5_PORT, 0x3D); /* Init it into mode2 */ + mad_write (MC6_PORT, 0x02); /* Enable WSS, Disable MPU and SB */ + mad_write (MC7_PORT, 0xCB); + mad_write (MC10_PORT, 0x11); + + if (!wss_init (hw_config)) + return 0; + +/* + * A temporary kludge which drops the device back to mode1. + * This removes problems with interrupts but disables full duplex. + * A better solution should be introduced later. + */ + mad_write (MC5_PORT, 0x1D); /* Disable mode2 */ + return wss_init (hw_config); +} + int probe_mad16 (struct address_info *hw_config) { @@ -313,7 +411,28 @@ if (!detect_mad16 ()) { - return 0; + if (inb (PASSWD_REG) != 0xff) + return 0; + +/* + * First relocate MC# registers to 0xe0e/0xe0f, disable password + */ + + outb (0xE4, PASSWD_REG); + outb (0x80, PASSWD_REG); + + board_type = C930; + + DDB (printk ("Detect using password = 0xE4\n")); + + for (i = 0xf8d; i <= 0xf93; i++) + DDB (printk ("port %03x = %02x\n", i, mad_read (i))); + + if (!detect_mad16 ()) + return 0; + + DDB (printk ("mad16.c: 82C930 detected\n")); + return init_c930 (hw_config); } else { @@ -408,8 +527,8 @@ return 1; } -long -attach_mad16 (long mem_start, struct address_info *hw_config) +void +attach_mad16 (struct address_info *hw_config) { static char interrupt_bits[12] = @@ -430,7 +549,7 @@ already_initialized = 1; if (!ad1848_detect (hw_config->io_base + 4, &ad_flags, mad16_osp)) - return mem_start; + return; /* * Set the IRQ and DMA addresses. @@ -438,7 +557,7 @@ bits = interrupt_bits[hw_config->irq]; if (bits == -1) - return mem_start; + return; outb (bits | 0x40, config_port); if ((inb (version_port) & 0x40) == 0) @@ -450,12 +569,21 @@ if (ad_flags & AD_F_CS4231 && dma2 != -1 && dma2 != dma) { + if (!((dma == 0 && dma2 == 1) || + (dma == 1 && dma2 == 0) || + (dma == 3 && dma2 == 0))) + { /* Unsupported combination. Try to swap channels */ + int tmp = dma; + + dma = dma2; + dma2 = tmp; + } + if ((dma == 0 && dma2 == 1) || (dma == 1 && dma2 == 0) || (dma == 3 && dma2 == 0)) { dma2_bit = 0x04; /* Enable capture DMA */ - } else { @@ -474,12 +602,10 @@ dma2, 0, hw_config->osp); request_region (hw_config->io_base, 4, "MAD16 WSS config"); - - return mem_start; } -long -attach_mad16_mpu (long mem_start, struct address_info *hw_config) +void +attach_mad16_mpu (struct address_info *hw_config) { if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ { @@ -490,26 +616,27 @@ else hw_config->io_base = 0x220; - return mad16_sb_dsp_init (mem_start, hw_config); -#else - return 0; + hw_config->name = "Mad16/Mozart"; + sb_dsp_init (hw_config); #endif + + return; } -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) +#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) if (!already_initialized) - return mem_start; + return; - return attach_mpu401 (mem_start, hw_config); -#else - return mem_start; + hw_config->driver_use_1 = SB_MIDI_ONLY; + hw_config->name = "Mad16/Mozart"; + attach_uart401 (hw_config); #endif } int probe_mad16_mpu (struct address_info *hw_config) { -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) +#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) static int mpu_attached = 0; static int valid_ports[] = {0x330, 0x320, 0x310, 0x300}; @@ -562,13 +689,15 @@ } mad_write (MC3_PORT, tmp | 0x04); - return mad16_sb_dsp_detect (hw_config); + hw_config->driver_use_1 = SB_MIDI_ONLY; + return sb_dsp_detect (hw_config); #else return 0; #endif } - tmp = 0x83; /* MPU-401 enable */ + tmp = mad_read (MC6_PORT) & 0x83; + tmp |= 0x80; /* MPU-401 enable */ /* * Set the MPU base bits @@ -609,7 +738,7 @@ } mad_write (MC6_PORT, tmp); /* Write MPU401 config */ - return probe_mpu401 (hw_config); + return probe_uart401 (hw_config); #else return 0; #endif @@ -632,13 +761,13 @@ #ifdef CONFIG_MIDI if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */ { - mad16_sb_dsp_unload (hw_config); + sb_dsp_unload (hw_config); return; } #endif -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) - unload_mpu401 (hw_config); +#if (defined(CONFIG_UART401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) + unload_uart401 (hw_config); #endif } diff -ur --new-file old/linux/drivers/sound/mad16_sb_midi.c new/linux/drivers/sound/mad16_sb_midi.c --- old/linux/drivers/sound/mad16_sb_midi.c Fri Apr 12 08:49:43 1996 +++ new/linux/drivers/sound/mad16_sb_midi.c Thu Jan 1 01:00:00 1970 @@ -1,357 +0,0 @@ -/* - * sound/mad16_sb_midi.c - * - * The low level driver for MAD16 SoundBlaster-DS-chip-based MIDI. - */ -/* - * Copyright by Hannu Savolainen 1993-1996 - * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include - -/* - * Modifications by Aaron Ucko 1995 - */ - -#include "sound_config.h" - -#if defined(CONFIG_MAD16) && defined(CONFIG_MIDI) - -#define sbc_base mad16_sb_base -#include "sb.h" - -static int input_opened = 0; -static int my_dev; -static int mad16_sb_base = 0x220; -static int mad16_sb_irq = 0; -static int mad16_sb_dsp_ok = 0; -static int mad16_sb_dsp_attached = 0; -static int *midi_osp; - -int mad16_sb_midi_mode = NORMAL_MIDI; -int mad16_sb_midi_busy = 0; - -int mad16_sb_duplex_midi = 0; -volatile int mad16_sb_intr_active = 0; - -void (*midi_input_intr) (int dev, unsigned char data); - -static void mad16_sb_midi_init (int model); - -static int -mad16_sb_dsp_command (unsigned char val) -{ - int i; - unsigned long limit; - - limit = jiffies + HZ / 10; /* - * The timeout is 0.1 seconds - */ - - /* - * Note! the i<500000 is an emergency exit. The mad16_sb_dsp_command() is sometimes - * called while interrupts are disabled. This means that the timer is - * disabled also. However the timeout situation is a abnormal condition. - * Normally the DSP should be ready to accept commands after just couple of - * loops. - */ - - for (i = 0; i < 500000 && jiffies < limit; i++) - { - if ((inb (DSP_STATUS) & 0x80) == 0) - { - outb (val, DSP_COMMAND); - return 1; - } - } - - printk ("MAD16 (SBP mode): DSP Command(%x) Timeout.\n", val); - printk ("IRQ conflict???\n"); - return 0; -} - -void -mad16_sbintr (int irq, void *dev_id, struct pt_regs *dummy) -{ - int status; - - unsigned long flags; - unsigned char data; - - status = inb (DSP_DATA_AVAIL); /* - * Clear interrupt - */ - - save_flags (flags); - cli (); - - data = inb (DSP_READ); - if (input_opened) - midi_input_intr (my_dev, data); - - restore_flags (flags); -} - -static int -mad16_sb_reset_dsp (void) -{ - int loopc; - - outb (1, DSP_RESET); - tenmicrosec (midi_osp); - outb (0, DSP_RESET); - tenmicrosec (midi_osp); - tenmicrosec (midi_osp); - tenmicrosec (midi_osp); - - for (loopc = 0; loopc < 1000 && !(inb (DSP_DATA_AVAIL) & 0x80); loopc++); /* - * Wait - * for - * data - * * - * available - * status - */ - - if (inb (DSP_READ) != 0xAA) - return 0; /* - * Sorry - */ - - return 1; -} - -int -mad16_sb_dsp_detect (struct address_info *hw_config) -{ - mad16_sb_base = hw_config->io_base; - mad16_sb_irq = hw_config->irq; - midi_osp = hw_config->osp; - - if (check_region (hw_config->io_base, 16)) - { - printk ("MAD16 SB MIDI: I/O base %x not free\n", hw_config->io_base); - return 0; - } - - if (mad16_sb_dsp_ok) - return 0; /* - * Already initialized - */ - if (!mad16_sb_reset_dsp ()) - return 0; - - return 1; /* - * Detected - */ -} - -long -mad16_sb_dsp_init (long mem_start, struct address_info *hw_config) -/* this function now just verifies the reported version and calls - * mad16_sb_midi_init -- everything else is done elsewhere */ -{ - - mad16_sb_dsp_attached = 1; - midi_osp = hw_config->osp; - if (snd_set_irq_handler (mad16_sb_irq, mad16_sbintr, "MAD16 SB MIDI", midi_osp) < 0) - { - printk ("MAD16 SB MIDI: IRQ not free\n"); - return mem_start; - } - - request_region (hw_config->io_base, 16, "mad16/Mozart MIDI"); - - conf_printf ("MAD16 MIDI (SB mode)", hw_config); - mad16_sb_midi_init (2); - - mad16_sb_dsp_ok = 1; - return mem_start; -} - -void -mad16_sb_dsp_unload (struct address_info *hw_config) -{ - if (!mad16_sb_dsp_attached) - return; - - release_region (hw_config->io_base, 16); - snd_release_irq (hw_config->irq); -} - -static int -mad16_sb_midi_open (int dev, int mode, - void (*input) (int dev, unsigned char data), - void (*output) (int dev) -) -{ - - if (!mad16_sb_dsp_ok) - { - printk ("MAD16_SB Error: MIDI hardware not installed\n"); - return -ENXIO; - } - - if (mad16_sb_midi_busy) - return -EBUSY; - - if (mode != OPEN_WRITE && !mad16_sb_duplex_midi) - { - if (num_midis == 1) - printk ("MAD16 (SBP mode): Midi input not currently supported\n"); - return -EPERM; - } - - mad16_sb_midi_mode = NORMAL_MIDI; - if (mode != OPEN_WRITE) - { - if (mad16_sb_intr_active) - return -EBUSY; - mad16_sb_midi_mode = UART_MIDI; - } - - if (mad16_sb_midi_mode == UART_MIDI) - { - mad16_sb_reset_dsp (); - - if (!mad16_sb_dsp_command (0x35)) - return -EIO; /* - * Enter the UART mode - */ - mad16_sb_intr_active = 1; - - input_opened = 1; - midi_input_intr = input; - } - - mad16_sb_midi_busy = 1; - - return 0; -} - -static void -mad16_sb_midi_close (int dev) -{ - if (mad16_sb_midi_mode == UART_MIDI) - { - mad16_sb_reset_dsp (); /* - * The only way to kill the UART mode - */ - } - mad16_sb_intr_active = 0; - mad16_sb_midi_busy = 0; - input_opened = 0; -} - -static int -mad16_sb_midi_out (int dev, unsigned char midi_byte) -{ - unsigned long flags; - - if (mad16_sb_midi_mode == NORMAL_MIDI) - { - save_flags (flags); - cli (); - if (mad16_sb_dsp_command (0x38)) - mad16_sb_dsp_command (midi_byte); - else - printk ("MAD16_SB Error: Unable to send a MIDI byte\n"); - restore_flags (flags); - } - else - mad16_sb_dsp_command (midi_byte); /* - * UART write - */ - - return 1; -} - -static int -mad16_sb_midi_start_read (int dev) -{ - if (mad16_sb_midi_mode != UART_MIDI) - { - printk ("MAD16 (SBP mode): MIDI input not implemented.\n"); - return -EPERM; - } - return 0; -} - -static int -mad16_sb_midi_end_read (int dev) -{ - if (mad16_sb_midi_mode == UART_MIDI) - { - mad16_sb_reset_dsp (); - mad16_sb_intr_active = 0; - } - return 0; -} - -static int -mad16_sb_midi_ioctl (int dev, unsigned cmd, caddr_t arg) -{ - return -EPERM; -} - -#define MIDI_SYNTH_NAME "pseudo-SoundBlaster Midi" -#define MIDI_SYNTH_CAPS 0 -#include "midi_synth.h" - -static struct midi_operations mad16_sb_midi_operations = -{ - {"MAD16 (SBP mode)", 0, 0, SNDCARD_MAD16}, - &std_midi_synth, - {0}, - mad16_sb_midi_open, - mad16_sb_midi_close, - mad16_sb_midi_ioctl, - mad16_sb_midi_out, - mad16_sb_midi_start_read, - mad16_sb_midi_end_read, - NULL, /* - * Kick - */ - NULL, /* - * command - */ - NULL, /* - * buffer_status - */ - NULL -}; - -static void -mad16_sb_midi_init (int model) -{ - if (num_midis >= MAX_MIDI_DEV) - { - printk ("Sound: Too many midi devices detected\n"); - return; - } - - std_midi_synth.midi_dev = num_midis; - my_dev = num_midis; - midi_devs[num_midis++] = &mad16_sb_midi_operations; -} - -#endif diff -ur --new-file old/linux/drivers/sound/maui.c new/linux/drivers/sound/maui.c --- old/linux/drivers/sound/maui.c Fri Apr 12 08:49:43 1996 +++ new/linux/drivers/sound/maui.c Sat Jul 6 10:31:42 1996 @@ -4,27 +4,11 @@ * The low level driver for Turtle Beach Maui and Tropez. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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 @@ -57,6 +41,10 @@ #ifdef HAVE_MAUI_BOOT #include "maui_boot.h" +#else +static unsigned char *maui_os = NULL; +static int maui_osLen = 0; + #endif static wait_handle *maui_sleeper = NULL; @@ -93,20 +81,20 @@ { - unsigned long tl; + unsigned long tlimit; if (HZ / 10) - current_set_timeout (tl = jiffies + (HZ / 10)); + current_set_timeout (tlimit = jiffies + (HZ / 10)); else - tl = (unsigned long) -1; - maui_sleep_flag.mode = WK_SLEEP; + tlimit = (unsigned long) -1; + maui_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&maui_sleeper); - if (!(maui_sleep_flag.mode & WK_WAKEUP)) + if (!(maui_sleep_flag.flags & WK_WAKEUP)) { - if (jiffies >= tl) - maui_sleep_flag.mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + maui_sleep_flag.flags |= WK_TIMEOUT; } - maui_sleep_flag.mode &= ~WK_SLEEP; + maui_sleep_flag.flags &= ~WK_SLEEP; }; if (current_got_fatal_signal ()) return 0; @@ -317,7 +305,7 @@ if (count < hdr_size) { printk ("Maui error: Patch header too short\n"); - return -EINVAL; + return -(EINVAL); } count -= hdr_size; @@ -327,7 +315,7 @@ * been transferred already. */ - memcpy_fromfs (&((char *) &header)[offs], &((addr)[offs]), hdr_size - offs); + memcpy_fromfs (&((char *) &header)[offs], &(addr)[offs], hdr_size - offs); if (count < header.len) { @@ -345,10 +333,10 @@ data = get_fs_byte (&((addr)[hdr_size + i])); if (i == 0 && !(data & 0x80)) - return -EINVAL; + return -(EINVAL); if (maui_write (data) == -1) - return -EIO; + return -(EIO); } if ((i = maui_read ()) != 0x80) @@ -356,7 +344,7 @@ if (i != -1) printk ("Maui: Error status %02x\n", i); - return -EIO; + return -(EIO); } return 0; @@ -377,7 +365,7 @@ if (snd_set_irq_handler (hw_config->irq, mauiintr, "Maui", maui_osp) < 0) return 0; - maui_sleep_flag.mode = WK_NONE; + maui_sleep_flag.flags = WK_NONE; /* * Initialize the processor if necessary */ @@ -448,15 +436,16 @@ return ret; } -long -attach_maui (long mem_start, struct address_info *hw_config) +void +attach_maui (struct address_info *hw_config) { int this_dev = num_midis; conf_printf ("Maui", hw_config); hw_config->irq *= -1; - mem_start = attach_mpu401 (mem_start, hw_config); + hw_config->name = "Maui"; + attach_mpu401 (hw_config); if (num_midis > this_dev) /* The MPU401 driver installed itself */ { @@ -477,7 +466,6 @@ else printk ("Maui: Can't install patch loader\n"); } - return mem_start; } void diff -ur --new-file old/linux/drivers/sound/midi_synth.c new/linux/drivers/sound/midi_synth.c --- old/linux/drivers/sound/midi_synth.c Fri Apr 12 08:49:43 1996 +++ new/linux/drivers/sound/midi_synth.c Sat Jul 6 10:31:42 1996 @@ -4,27 +4,11 @@ * High level midi sequencer manager for dumb MIDI interfaces. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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 @@ -291,7 +275,7 @@ { case SNDCTL_SYNTH_INFO: - memcpy_tofs ((&((char *) arg)[0]), synth_devs[dev]->info, sizeof (struct synth_info)); + memcpy_tofs (&((char *) arg)[0], synth_devs[dev]->info, sizeof (struct synth_info)); return 0; break; @@ -301,7 +285,7 @@ break; default: - return -EINVAL; + return -(EINVAL); } } @@ -453,7 +437,7 @@ struct midi_input_info *inc; if (orig_dev < 0 || orig_dev > num_midis) - return -ENXIO; + return -(ENXIO); midi2synth[orig_dev] = dev; sysex_state[dev] = 0; @@ -474,7 +458,7 @@ inc->m_prev_status = 0x00; restore_flags (flags); - sysex_sleep_flag.mode = WK_NONE; + sysex_sleep_flag.flags = WK_NONE; return 1; } @@ -519,13 +503,13 @@ if (format != SYSEX_PATCH) { printk ("MIDI Error: Invalid patch format (key) 0x%x\n", format); - return -EINVAL; + return -(EINVAL); } if (count < hdr_size) { printk ("MIDI Error: Patch header too short\n"); - return -EINVAL; + return -(EINVAL); } count -= hdr_size; @@ -535,7 +519,7 @@ * been transferred already. */ - memcpy_fromfs (&((char *) &sysex)[offs], &((addr)[offs]), hdr_size - offs); + memcpy_fromfs (&((char *) &sysex)[offs], &(addr)[offs], hdr_size - offs); if (count < sysex.len) { @@ -547,7 +531,7 @@ left = sysex.len; src_offs = 0; - sysex_sleep_flag.mode = WK_NONE; + sysex_sleep_flag.flags = WK_NONE; for (i = 0; i < left && !current_got_fatal_signal (); i++) { @@ -565,7 +549,7 @@ if (data != 0xf0) { printk ("Error: Sysex start missing\n"); - return -EINVAL; + return -(EINVAL); } } @@ -573,20 +557,20 @@ !current_got_fatal_signal ()) { - unsigned long tl; + unsigned long tlimit; if (1) - current_set_timeout (tl = jiffies + (1)); + current_set_timeout (tlimit = jiffies + (1)); else - tl = (unsigned long) -1; - sysex_sleep_flag.mode = WK_SLEEP; + tlimit = (unsigned long) -1; + sysex_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&sysex_sleeper); - if (!(sysex_sleep_flag.mode & WK_WAKEUP)) + if (!(sysex_sleep_flag.flags & WK_WAKEUP)) { - if (jiffies >= tl) - sysex_sleep_flag.mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + sysex_sleep_flag.flags |= WK_TIMEOUT; } - sysex_sleep_flag.mode &= ~WK_SLEEP; + sysex_sleep_flag.flags &= ~WK_SLEEP; }; /* Wait for timeout */ if (!first_byte && data & 0x80) @@ -668,7 +652,7 @@ int midi_synth_patchmgr (int dev, struct patmgr_info *rec) { - return -EINVAL; + return -(EINVAL); } void diff -ur --new-file old/linux/drivers/sound/midibuf.c new/linux/drivers/sound/midibuf.c --- old/linux/drivers/sound/midibuf.c Sun Mar 24 21:50:08 1996 +++ new/linux/drivers/sound/midibuf.c Sun Aug 18 09:46:49 1996 @@ -4,27 +4,11 @@ * Device file manager for /dev/midi# */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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 @@ -112,20 +96,20 @@ midi_devs[dev]->buffer_status (dev)) { - unsigned long tl; + unsigned long tlimit; if (HZ / 10) - current_set_timeout (tl = jiffies + (HZ / 10)); + current_set_timeout (tlimit = jiffies + (HZ / 10)); else - tl = (unsigned long) -1; - midi_sleep_flag[dev].mode = WK_SLEEP; + tlimit = (unsigned long) -1; + midi_sleep_flag[dev].flags = WK_SLEEP; module_interruptible_sleep_on (&midi_sleeper[dev]); - if (!(midi_sleep_flag[dev].mode & WK_WAKEUP)) + if (!(midi_sleep_flag[dev].flags & WK_WAKEUP)) { - if (jiffies >= tl) - midi_sleep_flag[dev].mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + midi_sleep_flag[dev].flags |= WK_TIMEOUT; } - midi_sleep_flag[dev].mode &= ~WK_SLEEP; + midi_sleep_flag[dev].flags &= ~WK_SLEEP; }; } @@ -145,9 +129,9 @@ if (SPACE_AVAIL (midi_in_buf[dev])) { QUEUE_BYTE (midi_in_buf[dev], data); - if ((input_sleep_flag[dev].mode & WK_SLEEP)) + if ((input_sleep_flag[dev].flags & WK_SLEEP)) { - input_sleep_flag[dev].mode = WK_WAKEUP; + input_sleep_flag[dev].flags = WK_WAKEUP; module_wake_up (&input_sleeper[dev]); }; } @@ -184,9 +168,9 @@ } if (DATA_AVAIL (midi_out_buf[dev]) < 100 && - (midi_sleep_flag[dev].mode & WK_SLEEP)) + (midi_sleep_flag[dev].flags & WK_SLEEP)) { - midi_sleep_flag[dev].mode = WK_WAKEUP; + midi_sleep_flag[dev].flags = WK_WAKEUP; module_wake_up (&midi_sleeper[dev]); }; } @@ -218,7 +202,7 @@ if (dev < 0 || dev >= num_midis) { printk ("Sound: Nonexistent MIDI interface %d\n", dev); - return -ENXIO; + return -(ENXIO); } /* @@ -233,31 +217,31 @@ parms[dev].prech_timeout = 0; - midi_in_buf[dev] = (struct midi_buf *) kmalloc (sizeof (struct midi_buf), GFP_KERNEL); + midi_in_buf[dev] = (struct midi_buf *) vmalloc (sizeof (struct midi_buf)); if (midi_in_buf[dev] == NULL) { printk ("midi: Can't allocate buffer\n"); midi_devs[dev]->close (dev); - return -EIO; + return -(EIO); } midi_in_buf[dev]->len = midi_in_buf[dev]->head = midi_in_buf[dev]->tail = 0; - midi_out_buf[dev] = (struct midi_buf *) kmalloc (sizeof (struct midi_buf), GFP_KERNEL); + midi_out_buf[dev] = (struct midi_buf *) vmalloc (sizeof (struct midi_buf)); if (midi_out_buf[dev] == NULL) { printk ("midi: Can't allocate buffer\n"); midi_devs[dev]->close (dev); - kfree (midi_in_buf[dev]); + vfree (midi_in_buf[dev]); midi_in_buf[dev] = NULL; - return -EIO; + return -(EIO); } midi_out_buf[dev]->len = midi_out_buf[dev]->head = midi_out_buf[dev]->tail = 0; open_devs++; - midi_sleep_flag[dev].mode = WK_NONE; - input_sleep_flag[dev].mode = WK_NONE; + midi_sleep_flag[dev].flags = WK_NONE; + input_sleep_flag[dev].flags = WK_NONE; if (open_devs < 2) /* This was first open */ { @@ -302,20 +286,20 @@ DATA_AVAIL (midi_out_buf[dev])) { - unsigned long tl; + unsigned long tlimit; if (0) - current_set_timeout (tl = jiffies + (0)); + current_set_timeout (tlimit = jiffies + (0)); else - tl = (unsigned long) -1; - midi_sleep_flag[dev].mode = WK_SLEEP; + tlimit = (unsigned long) -1; + midi_sleep_flag[dev].flags = WK_SLEEP; module_interruptible_sleep_on (&midi_sleeper[dev]); - if (!(midi_sleep_flag[dev].mode & WK_WAKEUP)) + if (!(midi_sleep_flag[dev].flags & WK_WAKEUP)) { - if (jiffies >= tl) - midi_sleep_flag[dev].mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + midi_sleep_flag[dev].flags |= WK_TIMEOUT; } - midi_sleep_flag[dev].mode &= ~WK_SLEEP; + midi_sleep_flag[dev].flags &= ~WK_SLEEP; }; /* * Sync */ @@ -329,8 +313,8 @@ midi_devs[dev]->close (dev); - kfree (midi_in_buf[dev]); - kfree (midi_out_buf[dev]); + vfree (midi_in_buf[dev]); + vfree (midi_out_buf[dev]); midi_in_buf[dev] = NULL; midi_out_buf[dev] = NULL; if (open_devs < 2) @@ -365,25 +349,25 @@ { { - unsigned long tl; + unsigned long tlimit; if (0) - current_set_timeout (tl = jiffies + (0)); + current_set_timeout (tlimit = jiffies + (0)); else - tl = (unsigned long) -1; - midi_sleep_flag[dev].mode = WK_SLEEP; + tlimit = (unsigned long) -1; + midi_sleep_flag[dev].flags = WK_SLEEP; module_interruptible_sleep_on (&midi_sleeper[dev]); - if (!(midi_sleep_flag[dev].mode & WK_WAKEUP)) + if (!(midi_sleep_flag[dev].flags & WK_WAKEUP)) { - if (jiffies >= tl) - midi_sleep_flag[dev].mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + midi_sleep_flag[dev].flags |= WK_TIMEOUT; } - midi_sleep_flag[dev].mode &= ~WK_SLEEP; + midi_sleep_flag[dev].flags &= ~WK_SLEEP; }; if (current_got_fatal_signal ()) { restore_flags (flags); - return -EINTR; + return -(EINTR); } n = SPACE_AVAIL (midi_out_buf[dev]); @@ -394,7 +378,7 @@ for (i = 0; i < n; i++) { - memcpy_fromfs ((char *) &tmp_data, &((buf)[c]), 1); + memcpy_fromfs ((char *) &tmp_data, &(buf)[c], 1); QUEUE_BYTE (midi_out_buf[dev], tmp_data); c++; } @@ -424,23 +408,23 @@ { { - unsigned long tl; + unsigned long tlimit; if (parms[dev].prech_timeout) - current_set_timeout (tl = jiffies + (parms[dev].prech_timeout)); + current_set_timeout (tlimit = jiffies + (parms[dev].prech_timeout)); else - tl = (unsigned long) -1; - input_sleep_flag[dev].mode = WK_SLEEP; + tlimit = (unsigned long) -1; + input_sleep_flag[dev].flags = WK_SLEEP; module_interruptible_sleep_on (&input_sleeper[dev]); - if (!(input_sleep_flag[dev].mode & WK_WAKEUP)) + if (!(input_sleep_flag[dev].flags & WK_WAKEUP)) { - if (jiffies >= tl) - input_sleep_flag[dev].mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + input_sleep_flag[dev].flags |= WK_TIMEOUT; } - input_sleep_flag[dev].mode &= ~WK_SLEEP; + input_sleep_flag[dev].flags &= ~WK_SLEEP; }; if (current_got_fatal_signal ()) - c = -EINTR; /* + c = -(EINTR); /* * The user is getting restless */ } @@ -457,7 +441,7 @@ while (c < n) { REMOVE_BYTE (midi_in_buf[dev], tmp_data); - memcpy_tofs (&((buf)[c]), (char *) &tmp_data, 1); + memcpy_tofs (&(buf)[c], (char *) &tmp_data, 1); c++; } } @@ -482,14 +466,14 @@ else printk ("/dev/midi%d: No coprocessor for this device\n", dev); - return -ENXIO; + return -(ENXIO); } else switch (cmd) { case SNDCTL_MIDI_PRETIME: - val = (int) get_fs_long ((long *) arg); + val = (int) get_user ((int *) arg); if (val < 0) val = 0; @@ -514,7 +498,7 @@ if (!DATA_AVAIL (midi_in_buf[dev])) { - input_sleep_flag[dev].mode = WK_SLEEP; + input_sleep_flag[dev].flags = WK_SLEEP; module_select_wait (&input_sleeper[dev], wait); return 0; } @@ -525,7 +509,7 @@ if (SPACE_AVAIL (midi_out_buf[dev])) { - midi_sleep_flag[dev].mode = WK_SLEEP; + midi_sleep_flag[dev].flags = WK_SLEEP; module_select_wait (&midi_sleeper[dev], wait); return 0; } @@ -540,10 +524,9 @@ } -long -MIDIbuf_init (long mem_start) +void +MIDIbuf_init (void) { - return mem_start; } #endif diff -ur --new-file old/linux/drivers/sound/mpu401.c new/linux/drivers/sound/mpu401.c --- old/linux/drivers/sound/mpu401.c Mon May 6 11:26:12 1996 +++ new/linux/drivers/sound/mpu401.c Sun Aug 18 09:46:49 1996 @@ -4,27 +4,11 @@ * The low level driver for Roland MPU-401 compatible Midi cards. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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 @@ -508,14 +492,14 @@ struct mpu_config *devc; if (dev < 0 || dev >= num_midis) - return -ENXIO; + return -(ENXIO); devc = &dev_conf[dev]; if (devc->opened) { printk ("MPU-401: Midi busy\n"); - return -EBUSY; + return -(EBUSY); } /* @@ -530,7 +514,7 @@ if (mpu401_status (devc) == 0xff) /* Bus float */ { printk ("MPU-401: Device not initialized properly\n"); - return -EIO; + return -(EIO); } reset_mpu401 (devc); } @@ -624,7 +608,7 @@ */ { printk ("MPU-401 commands not possible in the UART mode\n"); - return -EINVAL; + return -(EINVAL); } /* @@ -643,7 +627,7 @@ if (timeout-- <= 0) { printk ("MPU-401: Command (0x%x) timeout\n", (int) cmd->cmd); - return -EIO; + return -(EIO); } save_flags (flags); @@ -677,7 +661,7 @@ { restore_flags (flags); /* printk ("MPU: No ACK to command (0x%x)\n", (int) cmd->cmd); */ - return -EIO; + return -(EIO); } if (cmd->nr_args) @@ -689,7 +673,7 @@ { restore_flags (flags); printk ("MPU: Command (0x%x), parm send failed.\n", (int) cmd->cmd); - return -EIO; + return -(EIO); } } @@ -711,7 +695,7 @@ { restore_flags (flags); /* printk ("MPU: No response(%d) to command (0x%x)\n", i, (int) cmd->cmd); */ - return -EIO; + return -(EIO); } } @@ -796,7 +780,7 @@ switch (cmd) { case 1: - memcpy_fromfs ((char *) init_sequence, &(((char *) arg)[0]), sizeof (init_sequence)); + memcpy_fromfs ((char *) init_sequence, &((char *) arg)[0], sizeof (init_sequence)); return 0; break; @@ -804,9 +788,9 @@ if (!(devc->capabilities & MPU_CAP_INTLG)) /* No intelligent mode */ { printk ("MPU-401: Intelligent mode not supported by the HW\n"); - return -EINVAL; + return -(EINVAL); } - set_uart_mode (dev, devc, !get_fs_long ((long *) arg)); + set_uart_mode (dev, devc, !get_user ((int *) arg)); return 0; break; @@ -815,18 +799,18 @@ int ret; mpu_command_rec rec; - memcpy_fromfs ((char *) &rec, &(((char *) arg)[0]), sizeof (rec)); + memcpy_fromfs ((char *) &rec, &((char *) arg)[0], sizeof (rec)); if ((ret = mpu401_command (dev, &rec)) < 0) return ret; - memcpy_tofs ((&((char *) arg)[0]), (char *) &rec, sizeof (rec)); + memcpy_tofs (&((char *) arg)[0], (char *) &rec, sizeof (rec)); return 0; } break; default: - return -EINVAL; + return -(EINVAL); } } @@ -853,7 +837,7 @@ midi_dev = synth_devs[dev]->midi_dev; if (midi_dev < 0 || midi_dev > num_midis) - return -ENXIO; + return -(ENXIO); devc = &dev_conf[midi_dev]; @@ -861,7 +845,7 @@ { case SNDCTL_SYNTH_INFO: - memcpy_tofs ((&((char *) arg)[0]), &mpu_synth_info[midi_dev], sizeof (struct synth_info)); + memcpy_tofs (&((char *) arg)[0], &mpu_synth_info[midi_dev], sizeof (struct synth_info)); return 0; break; @@ -871,7 +855,7 @@ break; default: - return -EINVAL; + return -(EINVAL); } } @@ -885,7 +869,7 @@ if (midi_dev < 0 || midi_dev > num_midis) { - return -ENXIO; + return -(ENXIO); } devc = &dev_conf[midi_dev]; @@ -902,7 +886,7 @@ if (mpu401_status (devc) == 0xff) /* Bus float */ { printk ("MPU-401: Device not initialized properly\n"); - return -EIO; + return -(EIO); } reset_mpu401 (devc); } @@ -910,7 +894,7 @@ if (devc->opened) { printk ("MPU-401: Midi busy\n"); - return -EBUSY; + return -(EBUSY); } devc->mode = MODE_SYNTH; @@ -1047,8 +1031,8 @@ restore_flags (flags); } -long -attach_mpu401 (long mem_start, struct address_info *hw_config) +void +attach_mpu401 (struct address_info *hw_config) { unsigned long flags; char revision_char; @@ -1058,7 +1042,7 @@ if (num_midis >= MAX_MIDI_DEV) { printk ("MPU-401: Too many midi devices detected\n"); - return mem_start; + return; } devc = &dev_conf[num_midis]; @@ -1091,14 +1075,14 @@ if (!reset_mpu401 (devc)) { printk ("MPU401: Device didn't respond\n"); - return mem_start; + return; } if (!devc->shared_irq) if (snd_set_irq_handler (devc->irq, mpuintr, "mpu401", devc->osp) < 0) { printk ("MPU401: Failed to allocate IRQ%d\n", devc->irq); - return mem_start; + return; } save_flags (flags); @@ -1117,15 +1101,15 @@ devc->capabilities |= MPU_CAP_INTLG; /* Supports intelligent mode */ - mpu401_synth_operations[num_midis] = (struct synth_operations *) (sound_mem_blocks[sound_num_blocks] = kmalloc (sizeof (struct synth_operations), GFP_KERNEL)); + mpu401_synth_operations[num_midis] = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct synth_operations))); - if (sound_num_blocks < 1024) - sound_num_blocks++;; + if (sound_nblocks < 1024) + sound_nblocks++;; if (mpu401_synth_operations[num_midis] == NULL) { printk ("mpu401: Can't allocate memory\n"); - return mem_start; + return; } if (!(devc->capabilities & MPU_CAP_INTLG)) /* No intelligent mode */ @@ -1177,12 +1161,15 @@ devc->capabilities |= MPU_CAP_SYNC | MPU_CAP_FSK; - sprintf (mpu_synth_info[num_midis].name, - "MPU-401 %d.%d%c Midi interface #%d", - (int) (devc->version & 0xf0) >> 4, - devc->version & 0x0f, - revision_char, - n_mpu_devs); + if (hw_config->name) + sprintf (mpu_synth_info[num_midis].name, "%s (MPU401)", hw_config->name); + else + sprintf (mpu_synth_info[num_midis].name, + "MPU-401 %d.%d%c Midi interface #%d", + (int) (devc->version & 0xf0) >> 4, + devc->version & 0x0f, + revision_char, + n_mpu_devs); } strcpy (mpu401_midi_operations[num_midis].info.name, @@ -1199,7 +1186,6 @@ irq2dev[devc->irq] = num_midis; midi_devs[num_midis++] = &mpu401_midi_operations[devc->devno]; - return mem_start; } static int @@ -1478,7 +1464,7 @@ int midi_dev = sound_timer_devs[dev]->devlink; if (timer_open) - return -EBUSY; + return -(EBUSY); tmr_reset (); curr_tempo = 50; @@ -1604,7 +1590,7 @@ { case SNDCTL_TMR_SOURCE: { - int parm = (int) get_fs_long ((long *) arg) & timer_caps; + int parm = (int) get_user ((int *) arg) & timer_caps; if (parm != 0) { @@ -1642,7 +1628,7 @@ case SNDCTL_TMR_TIMEBASE: { - int val = (int) get_fs_long ((long *) arg); + int val = (int) get_user ((int *) arg); if (val) set_timebase (midi_dev, val); @@ -1653,7 +1639,7 @@ case SNDCTL_TMR_TEMPO: { - int val = (int) get_fs_long ((long *) arg); + int val = (int) get_user ((int *) arg); int ret; if (val) @@ -1676,14 +1662,14 @@ break; case SNDCTL_SEQ_CTRLRATE: - if (get_fs_long ((long *) arg) != 0) /* Can't change */ - return -EINVAL; + if (get_user ((int *) arg) != 0) /* Can't change */ + return -(EINVAL); return snd_ioctl_return ((int *) arg, ((curr_tempo * curr_timebase) + 30) / 60); break; case SNDCTL_TMR_METRONOME: - metronome_mode = (int) get_fs_long ((long *) arg); + metronome_mode = (int) get_user ((int *) arg); setup_metronome (midi_dev); return 0; break; @@ -1691,7 +1677,7 @@ default:; } - return -EINVAL; + return -(EINVAL); } static void diff -ur --new-file old/linux/drivers/sound/opl3.c new/linux/drivers/sound/opl3.c --- old/linux/drivers/sound/opl3.c Fri Apr 12 08:49:43 1996 +++ new/linux/drivers/sound/opl3.c Sat Jul 6 10:31:42 1996 @@ -4,27 +4,11 @@ * A low level driver for Yamaha YM3812 and OPL-3 -chips */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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 @@ -58,6 +42,7 @@ typedef struct opl_devinfo { + int base; int left_io, right_io; int nr_voice; int lv_map[MAX_VOICE]; @@ -133,12 +118,12 @@ { struct sbi_instrument ins; - memcpy_fromfs ((char *) &ins, &(((char *) arg)[0]), sizeof (ins)); + memcpy_fromfs ((char *) &ins, &((char *) arg)[0], sizeof (ins)); if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) { printk ("FM Error: Invalid instrument number %d\n", ins.channel); - return -EINVAL; + return -(EINVAL); } pmgr_inform (dev, PM_E_PATCH_LOADED, ins.channel, 0, 0, 0); @@ -149,7 +134,7 @@ case SNDCTL_SYNTH_INFO: devc->fm_info.nr_voices = (devc->nr_voice == 12) ? 6 : devc->nr_voice; - memcpy_tofs ((&((char *) arg)[0]), &devc->fm_info, sizeof (devc->fm_info)); + memcpy_tofs (&((char *) arg)[0], &devc->fm_info, sizeof (devc->fm_info)); return 0; break; @@ -164,7 +149,7 @@ break; default: - return -EINVAL; + return -(EINVAL); } } @@ -173,7 +158,7 @@ opl3_detect (int ioaddr, int *osp) { /* - * This function returns 1 if the FM chicp is present at the given I/O port + * This function returns 1 if the FM chip is present at the given I/O port * The detection algorithm plays with the timer built in the FM chip and * looks for a change in the status register. * @@ -190,9 +175,9 @@ return 0; - devc = (struct opl_devinfo *) (sound_mem_blocks[sound_num_blocks] = kmalloc (sizeof (*devc), GFP_KERNEL)); - if (sound_num_blocks < 1024) - sound_num_blocks++;; + devc = (struct opl_devinfo *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (*devc))); + if (sound_nblocks < 1024) + sound_nblocks++;; if (devc == NULL) { @@ -201,6 +186,7 @@ } devc->osp = osp; + devc->base = ioaddr; /* Reset timers 1 and 2 */ opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); @@ -252,7 +238,7 @@ } /* - * There is a FM chicp in this address. Detect the type (OPL2 to OPL4) + * There is a FM chip in this address. Detect the type (OPL2 to OPL4) */ if (signature == 0x06 && !force_opl3_mode) /* OPL2 */ @@ -319,7 +305,7 @@ } static int -opl3_kill_note (int dev, int voice, int note, int velocity) +opl3_kill_note (int devno, int voice, int note, int velocity) { struct physical_voice_info *map; @@ -797,7 +783,7 @@ } static void -opl3_reset (int dev) +opl3_reset (int devno) { int i; @@ -821,7 +807,7 @@ KSL_LEVEL + pv_map[devc->lv_map[i]].op[3], 0xff); } - opl3_kill_note (dev, i, 0, 64); + opl3_kill_note (devno, i, 0, 64); } if (devc->model == 2) @@ -841,7 +827,7 @@ int i; if (devc->busy) - return -EBUSY; + return -(EBUSY); devc->busy = 1; devc->v_alloc->max_voice = devc->nr_voice = (devc->model == 2) ? 18 : 9; @@ -887,15 +873,15 @@ if (count < sizeof (ins)) { printk ("FM Error: Patch record too short\n"); - return -EINVAL; + return -(EINVAL); } - memcpy_fromfs (&((char *) &ins)[offs], &((addr)[offs]), sizeof (ins) - offs); + memcpy_fromfs (&((char *) &ins)[offs], &(addr)[offs], sizeof (ins) - offs); if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) { printk ("FM Error: Invalid instrument number %d\n", ins.channel); - return -EINVAL; + return -(EINVAL); } ins.key = format; @@ -1055,7 +1041,7 @@ static int opl3_patchmgr (int dev, struct patmgr_info *rec) { - return -EINVAL; + return -(EINVAL); } static void @@ -1173,25 +1159,26 @@ opl3_setup_voice }; -long -opl3_init (long mem_start, int ioaddr, int *osp) +void +opl3_init (int ioaddr, int *osp) { int i; if (num_synths >= MAX_SYNTH_DEV) { printk ("OPL3 Error: Too many synthesizers\n"); - return mem_start; + return; } if (devc == NULL) { printk ("OPL3: Device control structure not initialized.\n"); - return mem_start; + return; } memset ((char *) devc, 0x00, sizeof (*devc)); devc->osp = osp; + devc->base = ioaddr; devc->nr_voice = 9; strcpy (devc->fm_info.name, "OPL2"); @@ -1257,7 +1244,6 @@ for (i = 0; i < SBFM_MAXINSTR; i++) devc->i_map[i].channel = -1; - return mem_start; } #endif diff -ur --new-file old/linux/drivers/sound/opl3.h new/linux/drivers/sound/opl3.h --- old/linux/drivers/sound/opl3.h Fri Apr 12 08:49:43 1996 +++ new/linux/drivers/sound/opl3.h Sat Jul 6 10:31:43 1996 @@ -2,27 +2,11 @@ * opl3.h - Definitions of the OPL-3 registers */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ /* @@ -160,7 +144,7 @@ * register offset). * * For 4 OP voices the connection bit is used in the - * both halfs (gives 4 ways to connect the operators). + * both halves (gives 4 ways to connect the operators). */ #define FEEDBACK_CONNECTION 0xc0 #define FEEDBACK_MASK 0x0e /* Valid just for 1st OP of a voice */ @@ -169,7 +153,7 @@ * In the 4 OP mode there is four possible configurations how the * operators can be connected together (in 2 OP modes there is just * AM or FM). The 4 OP connection mode is defined by the rightmost - * bit of the FEEDBACK_CONNECTION (0xC0-0xC8) on the both halfs. + * bit of the FEEDBACK_CONNECTION (0xC0-0xC8) on the both halves. * * First half Second half Mode * diff -ur --new-file old/linux/drivers/sound/os.h new/linux/drivers/sound/os.h --- old/linux/drivers/sound/os.h Sun Mar 24 21:49:45 1996 +++ new/linux/drivers/sound/os.h Tue Aug 20 16:36:20 1996 @@ -18,14 +18,11 @@ #include #include #include -#include -#include #include #include #include #include #include -#include #include #include #include @@ -40,7 +37,7 @@ #define TRUE 1 struct snd_wait { - int mode; + int flags; }; extern int sound_alloc_dma(int chn, char *deviceID); @@ -51,7 +48,7 @@ #define RUNTIME_DMA_ALLOC extern caddr_t sound_mem_blocks[1024]; -extern int sound_num_blocks; +extern int sound_nblocks; #undef PSEUDO_DMA_AUTOINIT #define ALLOW_BUFFER_MAPPING diff -ur --new-file old/linux/drivers/sound/pas.h new/linux/drivers/sound/pas.h --- old/linux/drivers/sound/pas.h Fri Apr 12 08:49:43 1996 +++ new/linux/drivers/sound/pas.h Thu Jan 1 01:00:00 1970 @@ -1,236 +0,0 @@ -/* */ -/* Port addresses and bit fields for the Media Vision Pro AudioSpectrum second generation sound cards. */ -/* */ -/* Feel free to use this header file in any application you create that has support for the Media Vision */ -/* Pro AudioSpectrum second generation sound cards. Other uses prohibited without prior permission. */ -/* */ -/* - cmetz@thor.tjhsst.edu */ -/* */ -/* Notes: */ -/* */ -/* * All of these ports go into the MVD101 multimedia controller chip, which then signals the other chips to do */ -/* the actual work. Many ports like the FM ones functionally attach directly to the destination chip though */ -/* they don't actually have a direct connection. */ -/* */ -/* * The PAS2 series cards have an MVD101 multimedia controller chip, the original PAS cards don't. The original */ -/* PAS cards are pretty defunct now, so no attempt is made here to support them. */ -/* */ -/* * The PAS2 series cards are all really different at the hardware level, though the MVD101 hides some of the */ -/* incompatibilities, there still are differences that need to be accounted for. */ -/* */ -/* Card CD-ROM interface PCM chip Mixer chip FM chip */ -/* PAS Plus Sony proprietary (Crystal?) 8-bit DAC National OPL3 */ -/* PAS 16 Zilog SCSI MVA416 16-bit Codec MVA508 OPL3 */ -/* CDPC Sony proprietary Sony 16-bit Codec National OPL3 */ -/* Fusion CD 16 Sony proprietary MVA416 16-bit Codec MVA508 OPL3 */ -/* Fusion CD Sony proprietary (Crystal?) 8-bit DAC National OPL3 */ -/* */ -#define PAS_DEFAULT_BASE 0x388 - -/* Symbolic Name Value R W Subsystem Description */ -#define SPEAKER_CONTROL 0x61 /* W PC speaker Control register */ -#define SPEAKER_CONTROL_GHOST 0x738B /* R W PC speaker Control ghost register */ -#define SPEAKER_TIMER_CONTROL 0x43 /* W PC speaker Timer control register */ -#define SPEAKER_TIMER_CONTROL_GHOST 0x778B /* R W PC speaker Timer control register ghost */ -#define SPEAKER_TIMER_DATA 0x42 /* W PC speaker Timer data register */ -#define SPEAKER_TIMER_DATA_GHOST 0x138A /* R W PC speaker Timer data register ghost */ - -#define WARM_BOOT 0x41 /* W Control Used to detect system warm boot */ -#define WARM_BOOT_GHOST 0x7789 /* ? W Control Use to get the card to fake warm boot */ -#define MASTER_DECODE 0x9A01 /* W Control Address >> 2 of card base address */ -#define PRESCALE_DIVIDER 0xBF8A /* R W PCM Ration between Codec clock and master clock */ -#define WAIT_STATE 0xBF88 /* R W Control Four-bit bus wait-state count (~140ns ea.) */ -#define BOARD_REV_ID 0x2789 /* R Control Extended Board Revision ID */ - -#define CHIP_REV 0xFF88 /* R 0=PAS, 1=PAS+, 2=CDPC, 3=PAS16C, 4=PAS16D */ - -#define SYSTEM_CONFIGURATION_1 0x8388 /* R W Control */ -# define S_C_1_PCS_ENABLE 0x01 /* R W PC speaker 1=enable, 0=disable PC speaker emulation */ -# define S_C_1_PCM_CLOCK_SELECT 0x02 /* R W PCM 1=14.31818Mhz/12, 0=28.224Mhz master clock */ -# define S_C_1_FM_EMULATE_CLOCK 0x04 /* R W FM 1=use 28.224Mhz/2, 0=use 14.31818Mhz clock */ -# define S_C_1_PCS_STEREO 0x10 /* R W PC speaker 1=enable PC speaker stereo effect, 0=disable */ -# define S_C_1_PCS_REALSOUND 0x20 /* R W PC speaker 1=enable RealSound enhancement, 0=disable */ -# define S_C_1_FORCE_EXT_RESET 0x40 /* R W Control Force external reset */ -# define S_C_1_FORCE_INT_RESET 0x80 /* R W Control Force internal reset */ -#define SYSTEM_CONFIGURATION_2 0x8389 /* R W Control */ -# define S_C_2_PCM_OVERSAMPLING 0x03 /* R W PCM 00=0x, 01=2x, 10=4x, 11=reserved */ -# define S_C_2_PCM_16_BIT 0x04 /* R W PCM 1=16-bit, 0=8-bit samples */ -#define SYSTEM_CONFIGURATION_3 0x838A /* R W Control */ -# define S_C_3_PCM_CLOCK_SELECT 0x02 /* R W PCM 1=use 1.008Mhz clock for PCM, 0=don't */ -#define SYSTEM_CONFIGURATION_4 0x838B /* R W Control CD-ROM interface controls */ - -#define IO_CONFIGURATION_1 0xF388 /* R W Control */ -# define I_C_1_BOOT_RESET_ENABLE 0x80 /* R W Control 1=reset board on warm boot, 0=don't */ -# define I_C_1_JOYSTICK_ENABLE 0x40 /* R W Control 1=enable joystick port, 0=don't */ -#define IO_CONFIGURATION_2 0xF389 /* R W Control */ -# define I_C_2_PCM_DMA_DISABLED 0x00 /* R W PCM PCM DMA disabled */ -#define IO_CONFIGURATION_3 0xF38A /* R W Control */ -# define I_C_3_PCM_IRQ_DISABLED 0x00 /* R W PCM PCM IRQ disabled */ - -#define COMPATIBILITY_ENABLE 0xF788 /* R W Control */ -# define C_E_MPU401_ENABLE 0x01 /* R W MIDI 1=enable, 0=disable MPU401 MIDI emulation */ -# define C_E_SB_ENABLE 0x02 /* R W PCM 1=enable, 0=disable Sound Blaster emulation */ -# define C_E_SB_ACTIVE 0x04 /* R PCM "Sound Blaster Interrupt active" */ -# define C_E_MPU401_ACTIVE 0x08 /* R MIDI "MPU UART mode active" */ -# define C_E_PCM_COMPRESSION 0x10 /* R W PCM 1=enable, 0=disabled compression */ -#define EMULATION_ADDRESS 0xF789 /* R W Control */ -# define E_A_SB_BASE 0x0f /* R W PCM bits A4-A7 for SB base port */ -# define E_A_MPU401_BASE 0xf0 /* R W MIDI bits A4-A7 for MPU401 base port */ -#define EMULATION_CONFIGURATION 0xFB8A /* R W ***** Only valid on newer PAS2 cards (?) ***** */ -# define E_C_MPU401_IRQ 0x07 /* R W MIDI MPU401 emulation IRQ */ -# define E_C_SB_IRQ 0x38 /* R W PCM SB emulation IRQ */ -# define E_C_SB_DMA 0xC0 /* R W PCM SB emulation DMA */ - -#define OPERATION_MODE_1 0xEF8B /* R Control */ -# define O_M_1_CDROM_TYPE 0x03 /* R CD-ROM 3=SCSI, 2=Sony, 0=no CD-ROM interface */ -# define O_M_1_FM_TYPE 0x04 /* R FM 1=stereo, 0=mono FM chip */ -# define O_M_1_PCM_TYPE 0x08 /* R PCM 1=16-bit Codec, 0=8-bit DAC */ -#define OPERATION_MODE_2 0xFF8B /* R Control */ -# define O_M_2_PCS_ENABLED 0x02 /* R PC speaker PC speaker emulation 1=enabled, 0=disabled */ -# define O_M_2_BUS_TIMING 0x10 /* R Control 1=AT bus timing, 0=XT bus timing */ -# define O_M_2_BOARD_REVISION 0xe0 /* R Control Board revision */ - -#define INTERRUPT_MASK 0x0B8B /* R W Control */ -# define I_M_FM_LEFT_IRQ_ENABLE 0x01 /* R W FM Enable FM left interrupt */ -# define I_M_FM_RIGHT_IRQ_ENABLE 0x02 /* R W FM Enable FM right interrupt */ -# define I_M_PCM_RATE_IRQ_ENABLE 0x04 /* R W PCM Enable Sample Rate interrupt */ -# define I_M_PCM_BUFFER_IRQ_ENABLE 0x08 /* R W PCM Enable Sample Buffer interrupt */ -# define I_M_MIDI_IRQ_ENABLE 0x10 /* R W MIDI Enable MIDI interrupt */ -# define I_M_BOARD_REV 0xE0 /* R Control Board revision */ - -#define INTERRUPT_STATUS 0x0B89 /* R W Control */ -# define I_S_FM_LEFT_IRQ 0x01 /* R W FM Left FM Interrupt Pending */ -# define I_S_FM_RIGHT_IRQ 0x02 /* R W FM Right FM Interrupt Pending */ -# define I_S_PCM_SAMPLE_RATE_IRQ 0x04 /* R W PCM Sample Rate Interrupt Pending */ -# define I_S_PCM_SAMPLE_BUFFER_IRQ 0x08 /* R W PCM Sample Buffer Interrupt Pending */ -# define I_S_MIDI_IRQ 0x10 /* R W MIDI MIDI Interrupt Pending */ -# define I_S_PCM_CHANNEL 0x20 /* R W PCM 1=right, 0=left */ -# define I_S_RESET_ACTIVE 0x40 /* R W Control Reset is active (Timed pulse not finished) */ -# define I_S_PCM_CLIPPING 0x80 /* R W PCM Clipping has occurred */ - -#define FILTER_FREQUENCY 0x0B8A /* R W Control */ -# define F_F_FILTER_DISABLED 0x00 /* R W Mixer No filter */ -# define F_F_MIXER_UNMUTE 0x20 /* R W Mixer 1=disable, 0=enable board mute */ -# define F_F_PCM_RATE_COUNTER 0x40 /* R W PCM 1=enable, 0=disable sample rate counter */ -# define F_F_PCM_BUFFER_COUNTER 0x80 /* R W PCM 1=enable, 0=disable sample buffer counter */ - -#define PAS_NONE 0 -#define PAS_PLUS 1 -#define PAS_CDPC 2 -#define PAS_16 3 -#define PAS_16D 4 - -#ifdef DEFINE_TRANSLATIONS - unsigned char I_C_2_PCM_DMA_translate[] = /* R W PCM PCM DMA channel value translations */ - { 4, 1, 2, 3, 0, 5, 6, 7 }; - unsigned char I_C_3_PCM_IRQ_translate[] = /* R W PCM PCM IRQ level value translation */ - { 0, 0, 1, 2, 3, 4, 5, 6, 0, 1, 7, 8, 9, 0, 10, 11 }; - unsigned char E_C_MPU401_IRQ_translate[] = /* R W MIDI MPU401 emulation IRQ value translation */ - { 0x00, 0x00, 0x01, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x01, 0x05, 0x06, 0x07 }; - unsigned char E_C_SB_IRQ_translate[] = /* R W PCM SB emulation IRQ translate */ - { 0x00, 0x00, 0x08, 0x10, 0x00, 0x18, 0x00, 0x20, 0x00, 0x08, 0x28, 0x30, 0x38, 0, 0 }; - unsigned char E_C_SB_DMA_translate[] = /* R W PCM SB emulation DMA translate */ - { 0x00, 0x40, 0x80, 0xC0, 0, 0, 0, 0 }; - unsigned char O_M_1_to_card[] = /* R W Control Translate (OM1 & 0x0f) to card type */ - { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 4, 0, 2, 3 }; -#else - extern unsigned char I_C_2_PCM_DMA_translate[]; /* R W PCM PCM DMA channel value translations */ - extern unsigned char I_C_3_PCM_IRQ_translate[]; /* R W PCM PCM IRQ level value translation */ - extern unsigned char E_C_MPU401_IRQ_translate[]; /* R W MIDI MPU401 emulation IRQ value translation */ - extern unsigned char E_C_SB_IRQ_translate[]; /* R W PCM SB emulation IRQ translate */ - extern unsigned char E_C_SB_DMA_translate[]; /* R W PCM SB emulation DMA translate */ - extern unsigned char O_M_1_to_card[]; /* R W Control Translate (OM1 & 0x0f) to card type */ -#endif - -#define PARALLEL_MIXER 0x078B /* W Mixer Documented for MVD101 as FM Mono Right decode?? */ -# define P_M_MV508_ADDRESS 0x80 /* W Mixer MVD508 Address/mixer select */ -# define P_M_MV508_DATA 0x00 -# define P_M_MV508_LEFT 0x20 /* W Mixer MVD508 Left channel select */ -# define P_M_MV508_RIGHT 0x40 /* W Mixer MVD508 Right channel select */ -# define P_M_MV508_BOTH 0x00 /* W Mixer MVD508 Both channel select */ -# define P_M_MV508_MIXER 0x10 /* W Mixer MVD508 Select a mixer (rather than a volume) */ -# define P_M_MV508_VOLUME 0x00 - -# define P_M_MV508_INPUTMIX 0x20 /* W Mixer MVD508 Select mixer A */ -# define P_M_MV508_OUTPUTMIX 0x00 /* W Mixer MVD508 Select mixer B */ - -# define P_M_MV508_MASTER_A 0x01 /* W Mixer MVD508 Master volume control A (output) */ -# define P_M_MV508_MASTER_B 0x02 /* W Mixer MVD508 Master volume control B (DSP input) */ -# define P_M_MV508_BASS 0x03 /* W Mixer MVD508 Bass control */ -# define P_M_MV508_TREBLE 0x04 /* W Mixer MVD508 Treble control */ -# define P_M_MV508_MODE 0x05 /* W Mixer MVD508 Master mode control */ - -# define P_M_MV508_LOUDNESS 0x04 /* W Mixer MVD508 Mode control - Loudness filter */ -# define P_M_MV508_ENHANCE_BITS 0x03 -# define P_M_MV508_ENHANCE_NONE 0x00 /* W Mixer MVD508 Mode control - No stereo enhancement */ -# define P_M_MV508_ENHANCE_40 0x01 /* W Mixer MVD508 Mode control - 40% stereo enhancement */ -# define P_M_MV508_ENHANCE_60 0x02 /* W Mixer MVD508 Mode control - 60% stereo enhancement */ -# define P_M_MV508_ENHANCE_80 0x03 /* W Mixer MVD508 Mode control - 80% stereo enhancement */ - -# define P_M_MV508_FM 0x00 /* W Mixer MVD508 Channel 0 - FM */ -# define P_M_MV508_IMIXER 0x01 /* W Mixer MVD508 Channel 1 - Input mixer (rec monitor) */ -# define P_M_MV508_LINE 0x02 /* W Mixer MVD508 Channel 2 - Line in */ -# define P_M_MV508_CDROM 0x03 /* W Mixer MVD508 Channel 3 - CD-ROM */ -# define P_M_MV508_MIC 0x04 /* W Mixer MVD508 Channel 4 - Microphone */ -# define P_M_MV508_PCM 0x05 /* W Mixer MVD508 Channel 5 - PCM */ -# define P_M_MV508_SPEAKER 0x06 /* W Mixer MVD508 Channel 6 - PC Speaker */ -# define P_M_MV508_SB 0x07 /* W Mixer MVD508 Channel 7 - SB DSP */ - -#define SERIAL_MIXER 0xB88 /* R W Control Serial mixer control (used other ways) */ -# define S_M_PCM_RESET 0x01 /* R W PCM Codec/DSP reset */ -# define S_M_FM_RESET 0x02 /* R W FM FM chip reset */ -# define S_M_SB_RESET 0x04 /* R W PCM SB emulation chip reset */ -# define S_M_MIXER_RESET 0x10 /* R W Mixer Mixer chip reset */ -# define S_M_INTEGRATOR_ENABLE 0x40 /* R W Speaker Enable PC speaker integrator (FORCE RealSound) */ -# define S_M_OPL3_DUAL_MONO 0x80 /* R W FM Set the OPL-3 to dual mono mode */ - -#define PCM_CONTROL 0xF8A /* R W PCM PCM Control Register */ -# define P_C_MIXER_CROSS_FIELD 0x0f -# define P_C_MIXER_CROSS_R_TO_R 0x01 /* R W Mixer Connect Right to Right */ -# define P_C_MIXER_CROSS_L_TO_R 0x02 /* R W Mixer Connect Left to Right */ -# define P_C_MIXER_CROSS_R_TO_L 0x04 /* R W Mixer Connect Right to Left */ -# define P_C_MIXER_CROSS_L_TO_L 0x08 /* R W Mixer Connect Left to Left */ -# define P_C_PCM_DAC_MODE 0x10 /* R W PCM Playback (DAC) mode */ -# define P_C_PCM_ADC_MODE 0x00 /* R W PCM Record (ADC) mode */ -# define P_C_PCM_MONO 0x20 /* R W PCM Mono mode */ -# define P_C_PCM_STEREO 0x00 /* R W PCM Stereo mode */ -# define P_C_PCM_ENABLE 0x40 /* R W PCM Enable PCM engine */ -# define P_C_PCM_DMA_ENABLE 0x80 /* R W PCM Enable DRQ */ - -#define SAMPLE_COUNTER_CONTROL 0x138B /* R W PCM Sample counter control register */ -# define S_C_C_SQUARE_WAVE 0x04 /* R W PCM Square wave generator (use for sample rate) */ -# define S_C_C_RATE 0x06 /* R W PCM Rate generator (use for sample buffer count) */ -# define S_C_C_LSB_THEN_MSB 0x30 /* R W PCM Change all 16 bits, LSB first, then MSB */ - - /* MVD101 and SDK documentations have S_C_C_SAMPLE_RATE and S_C_C_SAMPLE_BUFFER transposed. Only one works :-) */ -# define S_C_C_SAMPLE_RATE 0x00 /* R W PCM Select sample rate timer */ -# define S_C_C_SAMPLE_BUFFER 0x40 /* R W PCM Select sample buffer counter */ - -# define S_C_C_PC_SPEAKER 0x80 /* R W PCM Select PC speaker counter */ - -#define SAMPLE_RATE_TIMER 0x1388 /* W PCM Sample rate timer register (PCM wait interval) */ -#define SAMPLE_BUFFER_COUNTER 0x1389 /* R W PCM Sample buffer counter (DMA buffer size) */ - -#define MIDI_CONTROL 0x178b /* R W MIDI Midi control register */ -# define M_C_ENA_TSTAMP_IRQ 0x01 /* R W MIDI Enable Time Stamp Interrupts */ -# define M_C_ENA_TME_COMP_IRQ 0x02 /* R W MIDI Enable time compare interrupts */ -# define M_C_ENA_INPUT_IRQ 0x04 /* R W MIDI Enable input FIFO interrupts */ -# define M_C_ENA_OUTPUT_IRQ 0x08 /* R W MIDI Enable output FIFO interrupts */ -# define M_C_ENA_OUTPUT_HALF_IRQ 0x10 /* R W MIDI Enable output FIFO half full interrupts */ -# define M_C_RESET_INPUT_FIFO 0x20 /* R W MIDI Reset input FIFO pointer */ -# define M_C_RESET_OUTPUT_FIFO 0x40 /* R W MIDI Reset output FIFO pointer */ -# define M_C_ENA_THRU_MODE 0x80 /* R W MIDI Echo input to output (THRU) */ - -#define MIDI_STATUS 0x1B88 /* R W MIDI Midi (interrupt) status register */ -# define M_S_TIMESTAMP 0x01 /* R W MIDI Midi time stamp interrupt occurred */ -# define M_S_COMPARE 0x02 /* R W MIDI Midi compare time interrupt occurred */ -# define M_S_INPUT_AVAIL 0x04 /* R W MIDI Midi input data available interrupt occurred */ -# define M_S_OUTPUT_EMPTY 0x08 /* R W MIDI Midi output FIFO empty interrupt occurred */ -# define M_S_OUTPUT_HALF_EMPTY 0x10 /* R W MIDI Midi output FIFO half empty interrupt occurred */ -# define M_S_INPUT_OVERRUN 0x20 /* R W MIDI Midi input overrun error occurred */ -# define M_S_OUTPUT_OVERRUN 0x40 /* R W MIDI Midi output overrun error occurred */ -# define M_S_FRAMING_ERROR 0x80 /* R W MIDI Midi input framing error occurred */ - -#define MIDI_FIFO_STATUS 0x1B89 /* R W MIDI Midi fifo status */ -#define MIDI_DATA 0x178A /* R W MIDI Midi data register */ -#define MIDI_INPUT_AVAILABLE 0x0f /* RW MIDI */ diff -ur --new-file old/linux/drivers/sound/pas2_card.c new/linux/drivers/sound/pas2_card.c --- old/linux/drivers/sound/pas2_card.c Sun Mar 24 21:50:12 1996 +++ new/linux/drivers/sound/pas2_card.c Sat Jul 6 10:31:42 1996 @@ -4,47 +4,31 @@ * * Detection routine for the Pro Audio Spectrum cards. */ -/* - * Copyright by Hannu Savolainen 1993-1996 - * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include +#include #include "sound_config.h" #if defined(CONFIG_PAS) -#define DEFINE_TRANSLATIONS -#include "pas.h" +static unsigned char dma_bits[] = +{4, 1, 2, 3, 0, 5, 6, 7}; +static unsigned char irq_bits[] = +{0, 0, 1, 2, 3, 4, 5, 6, 0, 1, 7, 8, 9, 0, 10, 11}; +static unsigned char sb_irq_bits[] = +{0x00, 0x00, 0x08, 0x10, 0x00, 0x18, 0x00, 0x20, 0x00, 0x08, 0x28, 0x30, 0x38, 0, 0}; +static unsigned char sb_dma_bits[] = +{0x00, 0x40, 0x80, 0xC0, 0, 0, 0, 0}; /* * The Address Translation code is used to convert I/O register addresses to * be relative to the given base -register */ -int translat_code; +int translate_code; static int pas_intr_mask = 0; static int pas_irq = 0; +static int pas_sb_base = 0; int *pas_osp; @@ -54,11 +38,7 @@ /* * pas_read() and pas_write() are equivalents of inb and outb - */ -/* * These routines perform the I/O address translation required - */ -/* * to support other than the default base address */ extern void mix_write (unsigned char data, int ioaddr); @@ -66,19 +46,13 @@ unsigned char pas_read (int ioaddr) { - return inb (ioaddr ^ translat_code); + return inb (ioaddr ^ translate_code); } void pas_write (unsigned char data, int ioaddr) { - outb (data, ioaddr ^ translat_code); -} - -void -pas2_msg (char *foo) -{ - printk (" PAS2: %s.\n", foo); + outb (data, ioaddr ^ translate_code); } /******************* Begin of the Interrupt Handler ********************/ @@ -88,26 +62,23 @@ { int status; - status = pas_read (INTERRUPT_STATUS); - pas_write (status, INTERRUPT_STATUS); /* - * Clear interrupt - */ + status = pas_read (0x0B89); + pas_write (status, 0x0B89); /* Clear interrupt */ - if (status & I_S_PCM_SAMPLE_BUFFER_IRQ) + if (status & 0x08) { #ifdef CONFIG_AUDIO pas_pcm_interrupt (status, 1); #endif - status &= ~I_S_PCM_SAMPLE_BUFFER_IRQ; + status &= ~0x08; } - if (status & I_S_MIDI_IRQ) + if (status & 0x10) { #ifdef CONFIG_MIDI pas_midi_interrupt (); #endif - status &= ~I_S_MIDI_IRQ; + status &= ~0x10; } - } int @@ -118,7 +89,7 @@ pas_intr_mask |= mask; - pas_write (pas_intr_mask, INTERRUPT_MASK); + pas_write (pas_intr_mask, 0x0B8B); return 0; } @@ -129,7 +100,7 @@ return 0; pas_intr_mask &= ~mask; - pas_write (pas_intr_mask, INTERRUPT_MASK); + pas_write (pas_intr_mask, 0x0B8B); return 0; } @@ -146,41 +117,41 @@ pas_irq = hw_config->irq; - pas_write (0x00, INTERRUPT_MASK); + pas_write (0x00, 0x0B8B); + + pas_write (0x36, 0x138B); /* + * Local timer control * + * register + */ + + pas_write (0x36, 0x1388); /* + * Sample rate timer (16 bit) + */ + pas_write (0, 0x1388); + + pas_write (0x74, 0x138B); /* + * Local timer control * + * register + */ + + pas_write (0x74, 0x1389); /* + * Sample count register (16 + * * bit) + */ + pas_write (0, 0x1389); - pas_write (0x36, SAMPLE_COUNTER_CONTROL); /* - * Local timer control * - * register - */ - - pas_write (0x36, SAMPLE_RATE_TIMER); /* - * Sample rate timer (16 bit) - */ - pas_write (0, SAMPLE_RATE_TIMER); - - pas_write (0x74, SAMPLE_COUNTER_CONTROL); /* - * Local timer control * - * register - */ - - pas_write (0x74, SAMPLE_BUFFER_COUNTER); /* - * Sample count register (16 - * * bit) - */ - pas_write (0, SAMPLE_BUFFER_COUNTER); - - pas_write (F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER | F_F_MIXER_UNMUTE | 1, FILTER_FREQUENCY); - pas_write (P_C_PCM_DMA_ENABLE | P_C_PCM_MONO | P_C_PCM_DAC_MODE | P_C_MIXER_CROSS_L_TO_L | P_C_MIXER_CROSS_R_TO_R, PCM_CONTROL); - pas_write (S_M_PCM_RESET | S_M_FM_RESET | S_M_SB_RESET | S_M_MIXER_RESET /* - * | - * S_M_OPL3_DUAL_MONO - */ , SERIAL_MIXER); + pas_write (0x80 | 0x40 | 0x20 | 1, 0x0B8A); + pas_write (0x80 | 0x20 | 0x10 | 0x08 | 0x01, 0xF8A); + pas_write (0x01 | 0x02 | 0x04 | 0x10 /* + * | + * 0x80 + */ , 0xB88); - pas_write (I_C_1_BOOT_RESET_ENABLE + pas_write (0x80 #ifdef PAS_JOYSTICK_ENABLE - | I_C_1_JOYSTICK_ENABLE + | 0x40 #endif - ,IO_CONFIGURATION_1); + ,0xF388); if (pas_irq < 0 || pas_irq > 15) { @@ -189,10 +160,10 @@ } else { - int_ptrs = pas_read (IO_CONFIGURATION_3); - int_ptrs |= I_C_3_PCM_IRQ_translate[pas_irq] & 0xf; - pas_write (int_ptrs, IO_CONFIGURATION_3); - if (!I_C_3_PCM_IRQ_translate[pas_irq]) + int_ptrs = pas_read (0xF38A); + int_ptrs |= irq_bits[pas_irq] & 0xf; + pas_write (int_ptrs, 0xF38A); + if (!irq_bits[pas_irq]) { printk ("PAS2: Invalid IRQ %d", pas_irq); ok = 0; @@ -211,8 +182,8 @@ } else { - pas_write (I_C_2_PCM_DMA_translate[hw_config->dma], IO_CONFIGURATION_2); - if (!I_C_2_PCM_DMA_translate[hw_config->dma]) + pas_write (dma_bits[hw_config->dma], 0xF389); + if (!dma_bits[hw_config->dma]) { printk ("PAS2: Invalid DMA selection %d", hw_config->dma); ok = 0; @@ -237,29 +208,19 @@ #endif #ifdef BROKEN_BUS_CLOCK - pas_write (S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND | S_C_1_FM_EMULATE_CLOCK, SYSTEM_CONFIGURATION_1); + pas_write (0x01 | 0x10 | 0x20 | 0x04, 0x8388); #else /* - * pas_write(S_C_1_PCS_ENABLE, SYSTEM_CONFIGURATION_1); + * pas_write(0x01, 0x8388); */ - pas_write (S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND, SYSTEM_CONFIGURATION_1); + pas_write (0x01 | 0x10 | 0x20, 0x8388); #endif - pas_write (0x18, SYSTEM_CONFIGURATION_3); /* - * ??? - */ - - pas_write (F_F_MIXER_UNMUTE | 0x01, FILTER_FREQUENCY); /* - * Sets mute - * off and * - * selects - * filter - * rate * of - * 17.897 kHz - */ - pas_write (8, PRESCALE_DIVIDER); + pas_write (0x18, 0x838A); /* ??? */ + pas_write (0x20 | 0x01, 0x0B8A); /* Mute off, filter = 17.897 kHz */ + pas_write (8, 0xBF8A); - mix_write (P_M_MV508_ADDRESS | 5, PARALLEL_MIXER); - mix_write (5, PARALLEL_MIXER); + mix_write (0x80 | 5, 0x078B); + mix_write (5, 0x078B); #if !defined(DISABLE_SB_EMULATION) && defined(CONFIG_SB) @@ -272,42 +233,39 @@ /* * Turn on Sound Blaster compatibility - */ - /* * bit 1 = SB emulation - */ - /* * bit 0 = MPU401 emulation (CDPC only :-( ) */ - pas_write (0x02, COMPATIBILITY_ENABLE); + pas_write (0x02, 0xF788); /* * "Emulation address" */ - pas_write ((sb_config->io_base >> 4) & 0x0f, EMULATION_ADDRESS); + pas_write ((sb_config->io_base >> 4) & 0x0f, 0xF789); + pas_sb_base = sb_config->io_base; - if (!E_C_SB_DMA_translate[sb_config->dma]) + if (!sb_dma_bits[sb_config->dma]) printk ("\n\nPAS16 Warning: Invalid SB DMA %d\n\n", sb_config->dma); - if (!E_C_SB_IRQ_translate[sb_config->irq]) + if (!sb_irq_bits[sb_config->irq]) printk ("\n\nPAS16 Warning: Invalid SB IRQ %d\n\n", sb_config->irq); - irq_dma = E_C_SB_DMA_translate[sb_config->dma] | - E_C_SB_IRQ_translate[sb_config->irq]; + irq_dma = sb_dma_bits[sb_config->dma] | + sb_irq_bits[sb_config->irq]; - pas_write (irq_dma, EMULATION_CONFIGURATION); + pas_write (irq_dma, 0xFB8A); } else - pas_write (0x00, COMPATIBILITY_ENABLE); + pas_write (0x00, 0xF788); } #else - pas_write (0x00, COMPATIBILITY_ENABLE); + pas_write (0x00, 0xF788); #endif if (!ok) - pas2_msg ("Driver not enabled"); + printk ("PAS16: Driver not enabled\n"); return ok; } @@ -324,18 +282,12 @@ * you have something on base port 0x388. SO be forewarned. */ - outb (0xBC, MASTER_DECODE); /* - * Talk to first board - */ - outb (hw_config->io_base >> 2, MASTER_DECODE); /* - * Set base address - */ - translat_code = PAS_DEFAULT_BASE ^ hw_config->io_base; - pas_write (1, WAIT_STATE); /* - * One wait-state - */ + outb (0xBC, 0x9A01); /* Activate first board */ + outb (hw_config->io_base >> 2, 0x9A01); /* Set base address */ + translate_code = 0x388 ^ hw_config->io_base; + pas_write (1, 0xBF88); /* Select one wait states */ - board_id = pas_read (INTERRUPT_MASK); + board_id = pas_read (0x0B8B); if (board_id == 0xff) return 0; @@ -348,22 +300,22 @@ foo = board_id ^ 0xe0; - pas_write (foo, INTERRUPT_MASK); - foo = inb (INTERRUPT_MASK); - pas_write (board_id, INTERRUPT_MASK); + pas_write (foo, 0x0B8B); + foo = inb (0x0B8B); + pas_write (board_id, 0x0B8B); if (board_id != foo) /* * Not a PAS2 */ return 0; - pas_model = pas_read (CHIP_REV); + pas_model = pas_read (0xFF88); return pas_model; } -long -attach_pas_card (long mem_start, struct address_info *hw_config) +void +attach_pas_card (struct address_info *hw_config) { pas_irq = hw_config->irq; pas_osp = hw_config->osp; @@ -371,13 +323,13 @@ if (detect_pas_hw (hw_config)) { - if ((pas_model = pas_read (CHIP_REV))) + if ((pas_model = pas_read (0xFF88))) { char temp[100]; sprintf (temp, "%s rev %d", pas_model_names[(int) pas_model], - pas_read (BOARD_REV_ID)); + pas_read (0x2789)); conf_printf (temp, hw_config); } @@ -385,27 +337,23 @@ { #ifdef CONFIG_AUDIO - mem_start = pas_pcm_init (mem_start, hw_config); + pas_pcm_init (hw_config); #endif #if !defined(DISABLE_SB_EMULATION) && defined(CONFIG_SB) - sb_dsp_disable_midi (); /* - * The SB emulation don't support * - * midi - */ + sb_dsp_disable_midi (pas_sb_base); /* No MIDI capability */ #endif #ifdef CONFIG_MIDI - mem_start = pas_midi_init (mem_start); + pas_midi_init (); #endif pas_init_mixer (); } } - return mem_start; } int diff -ur --new-file old/linux/drivers/sound/pas2_midi.c new/linux/drivers/sound/pas2_midi.c --- old/linux/drivers/sound/pas2_midi.c Sun Mar 24 21:50:12 1996 +++ new/linux/drivers/sound/pas2_midi.c Sun Jun 30 11:31:09 1996 @@ -3,36 +3,11 @@ * * The low level driver for the PAS Midi Interface. */ -/* - * Copyright by Hannu Savolainen 1993-1996 - * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include +#include #include "sound_config.h" -#include "pas.h" - #if defined(CONFIG_PAS) && defined(CONFIG_MIDI) static int midi_busy = 0, input_opened = 0; @@ -59,19 +34,19 @@ if (midi_busy) { printk ("PAS2: Midi busy\n"); - return -EBUSY; + return -(EBUSY); } /* * Reset input and output FIFO pointers */ - pas_write (M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO, - MIDI_CONTROL); + pas_write (0x20 | 0x40, + 0x178b); save_flags (flags); cli (); - if ((err = pas_set_intr (I_M_MIDI_IRQ_ENABLE)) < 0) + if ((err = pas_set_intr (0x10)) < 0) return err; /* @@ -84,28 +59,28 @@ if (mode == OPEN_READ || mode == OPEN_READWRITE) { - ctrl |= M_C_ENA_INPUT_IRQ; /* - * Enable input - */ + ctrl |= 0x04; /* + * Enable input + */ input_opened = 1; } if (mode == OPEN_WRITE || mode == OPEN_READWRITE) { - ctrl |= M_C_ENA_OUTPUT_IRQ | /* - * Enable output - */ - M_C_ENA_OUTPUT_HALF_IRQ; + ctrl |= 0x08 | /* + * Enable output + */ + 0x10; } pas_write (ctrl, - MIDI_CONTROL); + 0x178b); /* * Acknowledge any pending interrupts */ - pas_write (0xff, MIDI_STATUS); + pas_write (0xff, 0x1B88); ofifo_bytes = 0; restore_flags (flags); @@ -122,9 +97,9 @@ /* * Reset FIFO pointers, disable intrs */ - pas_write (M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO, MIDI_CONTROL); + pas_write (0x20 | 0x40, 0x178b); - pas_remove_intr (I_M_MIDI_IRQ_ENABLE); + pas_remove_intr (0x10); midi_busy = 0; } @@ -133,7 +108,7 @@ { int fifo_space, x; - fifo_space = ((x = pas_read (MIDI_FIFO_STATUS)) >> 4) & 0x0f; + fifo_space = ((x = pas_read (0x1B89)) >> 4) & 0x0f; if (fifo_space == 15 || (fifo_space < 2 && ofifo_bytes > 13)) /* * Fifo @@ -147,7 +122,7 @@ ofifo_bytes++; - pas_write (midi_byte, MIDI_DATA); + pas_write (midi_byte, 0x178A); return 1; } @@ -219,7 +194,7 @@ static int pas_midi_ioctl (int dev, unsigned cmd, caddr_t arg) { - return -EINVAL; + return -(EINVAL); } static void @@ -257,18 +232,17 @@ NULL }; -long -pas_midi_init (long mem_start) +void +pas_midi_init (void) { if (num_midis >= MAX_MIDI_DEV) { printk ("Sound: Too many midi devices detected\n"); - return mem_start; + return; } std_midi_synth.midi_dev = my_dev = num_midis; midi_devs[num_midis++] = &pas_midi_operations; - return mem_start; } void @@ -278,32 +252,32 @@ int i, incount; unsigned long flags; - stat = pas_read (MIDI_STATUS); + stat = pas_read (0x1B88); - if (stat & M_S_INPUT_AVAIL) /* - * Input byte available + if (stat & 0x04) /* + * Input byte available */ { - incount = pas_read (MIDI_FIFO_STATUS) & 0x0f; /* - * Input FIFO count - */ + incount = pas_read (0x1B89) & 0x0f; /* + * Input FIFO count + */ if (!incount) incount = 16; for (i = 0; i < incount; i++) if (input_opened) { - midi_input_intr (my_dev, pas_read (MIDI_DATA)); + midi_input_intr (my_dev, pas_read (0x178A)); } else - pas_read (MIDI_DATA); /* + pas_read (0x178A); /* * Flush */ } - if (stat & (M_S_OUTPUT_EMPTY | M_S_OUTPUT_HALF_EMPTY)) + if (stat & (0x08 | 0x10)) { - if (!(stat & M_S_OUTPUT_EMPTY)) + if (!(stat & 0x08)) { ofifo_bytes = 8; } @@ -325,15 +299,15 @@ } - if (stat & M_S_OUTPUT_OVERRUN) + if (stat & 0x40) { - printk ("MIDI output overrun %x,%x,%d \n", pas_read (MIDI_FIFO_STATUS), stat, ofifo_bytes); + printk ("MIDI output overrun %x,%x,%d \n", pas_read (0x1B89), stat, ofifo_bytes); ofifo_bytes = 100; } - pas_write (stat, MIDI_STATUS); /* - * Acknowledge interrupts - */ + pas_write (stat, 0x1B88); /* + * Acknowledge interrupts + */ } #endif diff -ur --new-file old/linux/drivers/sound/pas2_mixer.c new/linux/drivers/sound/pas2_mixer.c --- old/linux/drivers/sound/pas2_mixer.c Sun Mar 24 21:50:13 1996 +++ new/linux/drivers/sound/pas2_mixer.c Sun Aug 18 09:46:49 1996 @@ -5,43 +5,21 @@ * * Mixer routines for the Pro Audio Spectrum cards. */ -/* - * Copyright by Hannu Savolainen 1993-1996 - * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ + #include - #include "sound_config.h" #if defined(CONFIG_PAS) -#include "pas.h" - -#define TRACE(what) /* (what) */ +#ifndef DEB +#define DEB(what) /* (what) */ +#endif -extern int translat_code; +extern int translate_code; extern char pas_model; extern int *pas_osp; +extern int pas_audiodev; static int rec_devices = (SOUND_MASK_MIC); /* Default recording source */ static int mode_control = 0; @@ -51,8 +29,8 @@ #define SUPPORTED_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \ SOUND_MASK_CD | SOUND_MASK_ALTPCM | SOUND_MASK_IMIX | \ - SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_RECLEV | \ - SOUND_MASK_MUTE | SOUND_MASK_ENHANCE | SOUND_MASK_LOUD) + SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_RECLEV) + static unsigned short levels[SOUND_MIXER_NRDEVICES] = { @@ -81,9 +59,9 @@ * sequence problem. */ - if (pas_model == PAS_16D) + if (pas_model == 4) { - outw (data | (data << 8), (ioaddr ^ translat_code) - 1); + outw (data | (data << 8), (ioaddr ^ translate_code) - 1); outb (0x80, 0); } else @@ -98,7 +76,7 @@ int right = right_vol * div / 100; - if (bits & P_M_MV508_MIXER) + if (bits & 0x10) { /* * Select input or output mixer */ @@ -106,20 +84,20 @@ right |= mixer; } - if (bits == P_M_MV508_BASS || bits == P_M_MV508_TREBLE) + if (bits == 0x03 || bits == 0x04) { /* * Bass and treble are mono devices */ - mix_write (P_M_MV508_ADDRESS | bits, PARALLEL_MIXER); - mix_write (left, PARALLEL_MIXER); + mix_write (0x80 | bits, 0x078B); + mix_write (left, 0x078B); right_vol = left_vol; } else { - mix_write (P_M_MV508_ADDRESS | P_M_MV508_LEFT | bits, PARALLEL_MIXER); - mix_write (left, PARALLEL_MIXER); - mix_write (P_M_MV508_ADDRESS | P_M_MV508_RIGHT | bits, PARALLEL_MIXER); - mix_write (right, PARALLEL_MIXER); + mix_write (0x80 | 0x20 | bits, 0x078B); + mix_write (left, 0x078B); + mix_write (0x80 | 0x40 | bits, 0x078B); + mix_write (right, 0x078B); } return (left_vol | (right_vol << 8)); @@ -128,8 +106,8 @@ void set_mode (int new_mode) { - mix_write (P_M_MV508_ADDRESS | P_M_MV508_MODE, PARALLEL_MIXER); - mix_write (new_mode, PARALLEL_MIXER); + mix_write (0x80 | 0x05, 0x078B); + mix_write (new_mode, 0x078B); mode_control = new_mode; } @@ -139,21 +117,21 @@ { int left, right, devmask, changed, i, mixer = 0; - TRACE (printk ("static int pas_mixer_set(int whichDev = %d, unsigned int level = %X)\n", whichDev, level)); + DEB (printk ("static int pas_mixer_set(int whichDev = %d, unsigned int level = %X)\n", whichDev, level)); left = level & 0x7f; right = (level & 0x7f00) >> 8; if (whichDev < SOUND_MIXER_NRDEVICES) if ((1 << whichDev) & rec_devices) - mixer = P_M_MV508_INPUTMIX; + mixer = 0x20; else - mixer = P_M_MV508_OUTPUTMIX; + mixer = 0x00; switch (whichDev) { case SOUND_MIXER_VOLUME: /* Master volume (0-63) */ - levels[whichDev] = mixer_output (right, left, 63, P_M_MV508_MASTER_A, 0); + levels[whichDev] = mixer_output (right, left, 63, 0x01, 0); break; /* @@ -161,67 +139,41 @@ * channel. */ case SOUND_MIXER_BASS: /* Bass (0-12) */ - levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_BASS, 0); + levels[whichDev] = mixer_output (right, left, 12, 0x03, 0); break; case SOUND_MIXER_TREBLE: /* Treble (0-12) */ - levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_TREBLE, 0); + levels[whichDev] = mixer_output (right, left, 12, 0x04, 0); break; case SOUND_MIXER_SYNTH: /* Internal synthesizer (0-31) */ - levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_FM, mixer); + levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x00, mixer); break; case SOUND_MIXER_PCM: /* PAS PCM (0-31) */ - levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_PCM, mixer); + levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x05, mixer); break; case SOUND_MIXER_ALTPCM: /* SB PCM (0-31) */ - levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SB, mixer); + levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x07, mixer); break; case SOUND_MIXER_SPEAKER: /* PC speaker (0-31) */ - levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SPEAKER, mixer); + levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x06, mixer); break; case SOUND_MIXER_LINE: /* External line (0-31) */ - levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_LINE, mixer); + levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x02, mixer); break; case SOUND_MIXER_CD: /* CD (0-31) */ - levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_CDROM, mixer); + levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x03, mixer); break; case SOUND_MIXER_MIC: /* External microphone (0-31) */ - levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_MIC, mixer); + levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x04, mixer); break; case SOUND_MIXER_IMIX: /* Recording monitor (0-31) (Output mixer only) */ - levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_IMIXER, - P_M_MV508_OUTPUTMIX); + levels[whichDev] = mixer_output (right, left, 31, 0x10 | 0x01, + 0x00); break; case SOUND_MIXER_RECLEV: /* Recording level (0-15) */ - levels[whichDev] = mixer_output (right, left, 15, P_M_MV508_MASTER_B, 0); + levels[whichDev] = mixer_output (right, left, 15, 0x02, 0); break; - case SOUND_MIXER_MUTE: - return 0; - break; - - case SOUND_MIXER_ENHANCE: - i = 0; - level &= 0x7f; - if (level) - i = (level / 20) - 1; - - mode_control &= ~P_M_MV508_ENHANCE_BITS; - mode_control |= P_M_MV508_ENHANCE_BITS; - set_mode (mode_control); - - if (i) - i = (i + 1) * 20; - return i; - break; - - case SOUND_MIXER_LOUD: - mode_control &= ~P_M_MV508_LOUDNESS; - if (level) - mode_control |= P_M_MV508_LOUDNESS; - set_mode (mode_control); - return !!level; /* 0 or 1 */ - break; case SOUND_MIXER_RECSRC: devmask = level & POSSIBLE_RECORDING_DEVICES; @@ -238,7 +190,7 @@ break; default: - return -EINVAL; + return -(EINVAL); } return (levels[whichDev]); @@ -251,26 +203,100 @@ { int foo; - TRACE (printk ("pas2_mixer.c: void pas_mixer_reset(void)\n")); + DEB (printk ("pas2_mixer.c: void pas_mixer_reset(void)\n")); for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++) pas_mixer_set (foo, levels[foo]); - set_mode (P_M_MV508_LOUDNESS | P_M_MV508_ENHANCE_40); + set_mode (0x04 | 0x01); } int pas_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) { - TRACE (printk ("pas2_mixer.c: int pas_mixer_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg)); + DEB (printk ("pas2_mixer.c: int pas_mixer_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg)); + + if (cmd == SOUND_MIXER_PRIVATE1) /* Set loudness bit */ + { + int level = get_user ((int *) arg); + + if (level == -1) /* Return current settings */ + { + if (mode_control & 0x04) + return snd_ioctl_return ((int *) arg, 1); + else + return snd_ioctl_return ((int *) arg, 0); + } + else + { + mode_control &= ~0x04; + if (level) + mode_control |= 0x04; + set_mode (mode_control); + return snd_ioctl_return ((int *) arg, !!level); /* 0 or 1 */ + } + } + + + if (cmd == SOUND_MIXER_PRIVATE2) /* Set enhance bit */ + { + int level = get_user ((int *) arg); + + if (level == -1) /* Return current settings */ + { + if (!(mode_control & 0x03)) + return snd_ioctl_return ((int *) arg, 0); + return snd_ioctl_return ((int *) arg, ((mode_control & 0x03) + 1) * 20); + } + else + { + int i = 0; + + level &= 0x7f; + if (level) + i = (level / 20) - 1; + + mode_control &= ~0x03; + mode_control |= i & 0x03; + set_mode (mode_control); + + if (i) + i = (i + 1) * 20; + + return i; + } + } + + if (cmd == SOUND_MIXER_PRIVATE3) /* Set mute bit */ + { + int level = get_user ((int *) arg); + + if (level == -1) /* Return current settings */ + { + return snd_ioctl_return ((int *) arg, + !(pas_read (0x0B8A) & + 0x20)); + } + else + { + if (level) + pas_write (pas_read (0x0B8A) & (~0x20), + 0x0B8A); + else + pas_write (pas_read (0x0B8A) | 0x20, + 0x0B8A); + + return !(pas_read (0x0B8A) & 0x20); + } + } if (((cmd >> 8) & 0xff) == 'M') { if (_IOC_DIR (cmd) & _IOC_WRITE) - return snd_ioctl_return ((int *) arg, pas_mixer_set (cmd & 0xff, get_fs_long ((long *) arg))); + return snd_ioctl_return ((int *) arg, pas_mixer_set (cmd & 0xff, get_user ((int *) arg))); else { /* - * Read parameters + * Read parameters */ switch (cmd & 0xff) @@ -296,32 +322,18 @@ return snd_ioctl_return ((int *) arg, 0); /* No special capabilities */ break; - case SOUND_MIXER_MUTE: - return snd_ioctl_return ((int *) arg, 0); /* No mute yet */ - break; - - case SOUND_MIXER_ENHANCE: - if (!(mode_control & P_M_MV508_ENHANCE_BITS)) - return snd_ioctl_return ((int *) arg, 0); - return snd_ioctl_return ((int *) arg, ((mode_control & P_M_MV508_ENHANCE_BITS) + 1) * 20); - break; - - case SOUND_MIXER_LOUD: - if (mode_control & P_M_MV508_LOUDNESS) - return snd_ioctl_return ((int *) arg, 1); - return snd_ioctl_return ((int *) arg, 0); - break; default: return snd_ioctl_return ((int *) arg, levels[cmd & 0xff]); } } } - return -EINVAL; + return -(EINVAL); } static struct mixer_operations pas_mixer_operations = { + "PAS16", "Pro Audio Spectrum 16", pas_mixer_ioctl }; @@ -332,7 +344,10 @@ pas_mixer_reset (); if (num_mixers < MAX_MIXER_DEV) - mixer_devs[num_mixers++] = &pas_mixer_operations; + { + audio_devs[pas_audiodev]->mixer_dev = num_mixers; + mixer_devs[num_mixers++] = &pas_mixer_operations; + } return 1; } diff -ur --new-file old/linux/drivers/sound/pas2_pcm.c new/linux/drivers/sound/pas2_pcm.c --- old/linux/drivers/sound/pas2_pcm.c Fri Apr 12 08:49:43 1996 +++ new/linux/drivers/sound/pas2_pcm.c Sun Aug 18 09:46:49 1996 @@ -4,40 +4,16 @@ * * The low level driver for the Pro Audio Spectrum ADC/DAC. */ -/* - * Copyright by Hannu Savolainen 1993-1996 - * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ + #include - #include "sound_config.h" -#include "pas.h" - #if defined(CONFIG_PAS) && defined(CONFIG_AUDIO) -#define TRACE(WHAT) /* - * * * (WHAT) */ +#ifndef DEB +#define DEB(WHAT) +#endif #define PAS_PCM_INTRBITS (0x08) /* @@ -56,7 +32,7 @@ static unsigned long pcm_count = 0; static unsigned short pcm_bitsok = 8; /* mask of OK bits */ static int pcm_busy = 0; -static int my_devnum = 0; +int pas_audiodev = 0; static int open_mode = 0; int @@ -65,6 +41,9 @@ int foo, tmp; unsigned long flags; + if (arg == 0) + return pcm_speed; + if (arg > 44100) arg = 44100; if (arg < 5000) @@ -83,7 +62,7 @@ pcm_speed = arg; - tmp = pas_read (FILTER_FREQUENCY); + tmp = pas_read (0x0B8A); /* * Set anti-aliasing filters according to sample rate. You really *NEED* @@ -92,32 +71,36 @@ * These filters apply to the selected "recording" source. * I (pfw) don't know the encoding of these 5 bits. The values shown * come from the SDK found on ftp.uwp.edu:/pub/msdos/proaudio/. + * + * I cleared bit 5 of these values, since that bit controls the master + * mute flag. (Olav Wölfelschneider) + * */ #if !defined NO_AUTO_FILTER_SET tmp &= 0xe0; if (pcm_speed >= 2 * 17897) - tmp |= 0x21; + tmp |= 0x01; else if (pcm_speed >= 2 * 15909) - tmp |= 0x22; + tmp |= 0x02; else if (pcm_speed >= 2 * 11931) - tmp |= 0x29; + tmp |= 0x09; else if (pcm_speed >= 2 * 8948) - tmp |= 0x31; + tmp |= 0x11; else if (pcm_speed >= 2 * 5965) - tmp |= 0x39; + tmp |= 0x19; else if (pcm_speed >= 2 * 2982) - tmp |= 0x24; + tmp |= 0x04; pcm_filter = tmp; #endif save_flags (flags); cli (); - pas_write (tmp & ~(F_F_PCM_RATE_COUNTER | F_F_PCM_BUFFER_COUNTER), FILTER_FREQUENCY); - pas_write (S_C_C_SAMPLE_RATE | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL); - pas_write (foo & 0xff, SAMPLE_RATE_TIMER); - pas_write ((foo >> 8) & 0xff, SAMPLE_RATE_TIMER); - pas_write (tmp, FILTER_FREQUENCY); + pas_write (tmp & ~(0x40 | 0x80), 0x0B8A); + pas_write (0x00 | 0x30 | 0x04, 0x138B); + pas_write (foo & 0xff, 0x1388); + pas_write ((foo >> 8) & 0xff, 0x1388); + pas_write (tmp, 0x0B8A); restore_flags (flags); @@ -133,7 +116,7 @@ if (arg != pcm_channels) { - pas_write (pas_read (PCM_CONTROL) ^ P_C_PCM_MONO, PCM_CONTROL); + pas_write (pas_read (0xF8A) ^ 0x20, 0xF8A); pcm_channels = arg; pcm_set_speed (pcm_speed); /* @@ -147,12 +130,15 @@ int pcm_set_bits (int arg) { + if (arg == 0) + return pcm_bits; + if ((arg & pcm_bitsok) != arg) return pcm_bits; if (arg != pcm_bits) { - pas_write (pas_read (SYSTEM_CONFIGURATION_2) ^ S_C_2_PCM_16_BIT, SYSTEM_CONFIGURATION_2); + pas_write (pas_read (0x8389) ^ 0x04, 0x8389); pcm_bits = arg; } @@ -161,16 +147,16 @@ } static int -pas_pcm_ioctl (int dev, unsigned int cmd, caddr_t arg, int local) +pas_audio_ioctl (int dev, unsigned int cmd, caddr_t arg, int local) { - TRACE (printk ("pas2_pcm.c: static int pas_pcm_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg)); + DEB (printk ("pas2_pcm.c: static int pas_audio_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg)); switch (cmd) { case SOUND_PCM_WRITE_RATE: if (local) return pcm_set_speed ((int) arg); - return snd_ioctl_return ((int *) arg, pcm_set_speed (get_fs_long ((long *) arg))); + return snd_ioctl_return ((int *) arg, pcm_set_speed (get_user ((int *) arg))); break; case SOUND_PCM_READ_RATE: @@ -182,13 +168,13 @@ case SNDCTL_DSP_STEREO: if (local) return pcm_set_channels ((int) arg + 1) - 1; - return snd_ioctl_return ((int *) arg, pcm_set_channels (get_fs_long ((long *) arg) + 1) - 1); + return snd_ioctl_return ((int *) arg, pcm_set_channels (get_user ((int *) arg) + 1) - 1); break; case SOUND_PCM_WRITE_CHANNELS: if (local) return pcm_set_channels ((int) arg); - return snd_ioctl_return ((int *) arg, pcm_set_channels (get_fs_long ((long *) arg))); + return snd_ioctl_return ((int *) arg, pcm_set_channels (get_user ((int *) arg))); break; case SOUND_PCM_READ_CHANNELS: @@ -200,7 +186,7 @@ case SNDCTL_DSP_SETFMT: if (local) return pcm_set_bits ((int) arg); - return snd_ioctl_return ((int *) arg, pcm_set_bits (get_fs_long ((long *) arg))); + return snd_ioctl_return ((int *) arg, pcm_set_bits (get_user ((int *) arg))); break; case SOUND_PCM_READ_BITS: @@ -211,9 +197,9 @@ case SOUND_PCM_WRITE_FILTER: /* * NOT YET IMPLEMENTED */ - if (get_fs_long ((long *) arg) > 1) - return -EINVAL; - pcm_filter = get_fs_long ((long *) arg); + if (get_user ((int *) arg) > 1) + return -(EINVAL); + pcm_filter = get_user ((int *) arg); break; case SOUND_PCM_READ_FILTER: @@ -221,34 +207,34 @@ break; default: - return -EINVAL; + return -(EINVAL); } - return -EINVAL; + return -(EINVAL); } static void -pas_pcm_reset (int dev) +pas_audio_reset (int dev) { - TRACE (printk ("pas2_pcm.c: static void pas_pcm_reset(void)\n")); + DEB (printk ("pas2_pcm.c: static void pas_audio_reset(void)\n")); - pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE, PCM_CONTROL); + pas_write (pas_read (0xF8A) & ~0x40, 0xF8A); } static int -pas_pcm_open (int dev, int mode) +pas_audio_open (int dev, int mode) { int err; unsigned long flags; - TRACE (printk ("pas2_pcm.c: static int pas_pcm_open(int mode = %X)\n", mode)); + DEB (printk ("pas2_pcm.c: static int pas_audio_open(int mode = %X)\n", mode)); save_flags (flags); cli (); if (pcm_busy) { restore_flags (flags); - return -EBUSY; + return -(EBUSY); } pcm_busy = 1; @@ -265,16 +251,16 @@ } static void -pas_pcm_close (int dev) +pas_audio_close (int dev) { unsigned long flags; - TRACE (printk ("pas2_pcm.c: static void pas_pcm_close(void)\n")); + DEB (printk ("pas2_pcm.c: static void pas_audio_close(void)\n")); save_flags (flags); cli (); - pas_pcm_reset (dev); + pas_audio_reset (dev); pas_remove_intr (PAS_PCM_INTRBITS); pcm_mode = PCM_NON; @@ -283,12 +269,12 @@ } static void -pas_pcm_output_block (int dev, unsigned long buf, int count, - int intrflag, int restart_dma) +pas_audio_output_block (int dev, unsigned long buf, int count, + int intrflag, int restart_dma) { unsigned long flags, cnt; - TRACE (printk ("pas2_pcm.c: static void pas_pcm_output_block(char *buf = %P, int count = %X)\n", buf, count)); + DEB (printk ("pas2_pcm.c: static void pas_audio_output_block(char *buf = %P, int count = %X)\n", buf, count)); cnt = count; if (audio_devs[dev]->dmachan1 > 3) @@ -304,8 +290,8 @@ save_flags (flags); cli (); - pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE, - PCM_CONTROL); + pas_write (pas_read (0xF8A) & ~0x40, + 0xF8A); if (restart_dma) DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); @@ -315,17 +301,17 @@ if (count != pcm_count) { - pas_write (pas_read (FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY); - pas_write (S_C_C_SAMPLE_BUFFER | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL); - pas_write (count & 0xff, SAMPLE_BUFFER_COUNTER); - pas_write ((count >> 8) & 0xff, SAMPLE_BUFFER_COUNTER); - pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY); + pas_write (pas_read (0x0B8A) & ~0x80, 0x0B8A); + pas_write (0x40 | 0x30 | 0x04, 0x138B); + pas_write (count & 0xff, 0x1389); + pas_write ((count >> 8) & 0xff, 0x1389); + pas_write (pas_read (0x0B8A) | 0x80, 0x0B8A); pcm_count = count; } - pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY); + pas_write (pas_read (0x0B8A) | 0x80 | 0x40, 0x0B8A); #ifdef NO_TRIGGER - pas_write (pas_read (PCM_CONTROL) | P_C_PCM_ENABLE | P_C_PCM_DAC_MODE, PCM_CONTROL); + pas_write (pas_read (0xF8A) | 0x40 | 0x10, 0xF8A); #endif pcm_mode = PCM_DAC; @@ -334,19 +320,19 @@ } static void -pas_pcm_start_input (int dev, unsigned long buf, int count, - int intrflag, int restart_dma) +pas_audio_start_input (int dev, unsigned long buf, int count, + int intrflag, int restart_dma) { unsigned long flags; int cnt; - TRACE (printk ("pas2_pcm.c: static void pas_pcm_start_input(char *buf = %P, int count = %X)\n", buf, count)); + DEB (printk ("pas2_pcm.c: static void pas_audio_start_input(char *buf = %P, int count = %X)\n", buf, count)); cnt = count; if (audio_devs[dev]->dmachan1 > 3) cnt >>= 1; - if (audio_devs[my_devnum]->flags & DMA_AUTOMODE && + if (audio_devs[pas_audiodev]->flags & DMA_AUTOMODE && intrflag && cnt == pcm_count) return; /* @@ -364,17 +350,17 @@ if (count != pcm_count) { - pas_write (pas_read (FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY); - pas_write (S_C_C_SAMPLE_BUFFER | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL); - pas_write (count & 0xff, SAMPLE_BUFFER_COUNTER); - pas_write ((count >> 8) & 0xff, SAMPLE_BUFFER_COUNTER); - pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY); + pas_write (pas_read (0x0B8A) & ~0x80, 0x0B8A); + pas_write (0x40 | 0x30 | 0x04, 0x138B); + pas_write (count & 0xff, 0x1389); + pas_write ((count >> 8) & 0xff, 0x1389); + pas_write (pas_read (0x0B8A) | 0x80, 0x0B8A); pcm_count = count; } - pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY); + pas_write (pas_read (0x0B8A) | 0x80 | 0x40, 0x0B8A); #ifdef NO_TRIGGER - pas_write ((pas_read (PCM_CONTROL) | P_C_PCM_ENABLE) & ~P_C_PCM_DAC_MODE, PCM_CONTROL); + pas_write ((pas_read (0xF8A) | 0x40) & ~0x10, 0xF8A); #endif pcm_mode = PCM_ADC; @@ -384,7 +370,7 @@ #ifndef NO_TRIGGER static void -pas_pcm_trigger (int dev, int state) +pas_audio_trigger (int dev, int state) { unsigned long flags; @@ -393,75 +379,74 @@ state &= open_mode; if (state & PCM_ENABLE_OUTPUT) - pas_write (pas_read (PCM_CONTROL) | P_C_PCM_ENABLE | P_C_PCM_DAC_MODE, PCM_CONTROL); + pas_write (pas_read (0xF8A) | 0x40 | 0x10, 0xF8A); else if (state & PCM_ENABLE_INPUT) - pas_write ((pas_read (PCM_CONTROL) | P_C_PCM_ENABLE) & ~P_C_PCM_DAC_MODE, PCM_CONTROL); + pas_write ((pas_read (0xF8A) | 0x40) & ~0x10, 0xF8A); else - pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE, PCM_CONTROL); + pas_write (pas_read (0xF8A) & ~0x40, 0xF8A); restore_flags (flags); } #endif static int -pas_pcm_prepare_for_input (int dev, int bsize, int bcount) +pas_audio_prepare_for_input (int dev, int bsize, int bcount) { return 0; } static int -pas_pcm_prepare_for_output (int dev, int bsize, int bcount) +pas_audio_prepare_for_output (int dev, int bsize, int bcount) { return 0; } -static struct audio_operations pas_pcm_operations = +static struct audio_driver pas_audio_driver = { - "Pro Audio Spectrum", - DMA_AUTOMODE, - AFMT_U8 | AFMT_S16_LE, + pas_audio_open, + pas_audio_close, + pas_audio_output_block, + pas_audio_start_input, + pas_audio_ioctl, + pas_audio_prepare_for_input, + pas_audio_prepare_for_output, + pas_audio_reset, + pas_audio_reset, NULL, - pas_pcm_open, - pas_pcm_close, - pas_pcm_output_block, - pas_pcm_start_input, - pas_pcm_ioctl, - pas_pcm_prepare_for_input, - pas_pcm_prepare_for_output, - pas_pcm_reset, - pas_pcm_reset, NULL, NULL, NULL, + pas_audio_trigger +}; + +static struct audio_operations pas_audio_operations = +{ + "Pro Audio Spectrum", + DMA_AUTOMODE, + AFMT_U8 | AFMT_S16_LE, NULL, -#ifndef NO_TRIGGER - pas_pcm_trigger -#else - NULL -#endif + &pas_audio_driver }; -long -pas_pcm_init (long mem_start, struct address_info *hw_config) +void +pas_pcm_init (struct address_info *hw_config) { - TRACE (printk ("pas2_pcm.c: long pas_pcm_init(long mem_start = %X)\n", mem_start)); + DEB (printk ("pas2_pcm.c: long pas_pcm_init()\n")); pcm_bitsok = 8; - if (pas_read (OPERATION_MODE_1) & O_M_1_PCM_TYPE) + if (pas_read (0xEF8B) & 0x08) pcm_bitsok |= 16; pcm_set_speed (DSP_DEFAULT_SPEED); if (num_audiodevs < MAX_AUDIO_DEV) { - audio_devs[my_devnum = num_audiodevs++] = &pas_pcm_operations; - audio_devs[my_devnum]->dmachan1 = hw_config->dma; - audio_devs[my_devnum]->buffsize = DSP_BUFFSIZE; + audio_devs[pas_audiodev = num_audiodevs++] = &pas_audio_operations; + audio_devs[pas_audiodev]->dmachan1 = hw_config->dma; + audio_devs[pas_audiodev]->buffsize = DSP_BUFFSIZE; } else printk ("PAS2: Too many PCM devices available\n"); - - return mem_start; } void @@ -476,21 +461,21 @@ * block before the PCM chip proceeds to the next sample */ - if (!(audio_devs[my_devnum]->flags & DMA_AUTOMODE)) + if (!(audio_devs[pas_audiodev]->flags & DMA_AUTOMODE)) { - pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE, - PCM_CONTROL); + pas_write (pas_read (0xF8A) & ~0x40, + 0xF8A); } switch (pcm_mode) { case PCM_DAC: - DMAbuf_outputintr (my_devnum, 1); + DMAbuf_outputintr (pas_audiodev, 1); break; case PCM_ADC: - DMAbuf_inputintr (my_devnum); + DMAbuf_inputintr (pas_audiodev); break; default: diff -ur --new-file old/linux/drivers/sound/patmgr.c new/linux/drivers/sound/patmgr.c --- old/linux/drivers/sound/patmgr.c Fri Apr 12 08:49:43 1996 +++ new/linux/drivers/sound/patmgr.c Sat Jul 6 10:31:42 1996 @@ -4,27 +4,11 @@ * The patch manager interface for the /dev/sequencer */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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 @@ -59,13 +43,13 @@ pmgr_open (int dev) { if (dev < 0 || dev >= num_synths) - return -ENXIO; + return -(ENXIO); if (pmgr_opened[dev]) - return -EBUSY; + return -(EBUSY); pmgr_opened[dev] = 1; - server_wait_flag[dev].mode = WK_NONE; + server_wait_flag[dev].flags = WK_NONE; return 0; } @@ -80,11 +64,11 @@ { mbox[dev]->key = PM_ERROR; - mbox[dev]->parm1 = -EIO; + mbox[dev]->parm1 = -(EIO); - if ((appl_wait_flag.mode & WK_SLEEP)) + if ((appl_wait_flag.flags & WK_SLEEP)) { - appl_wait_flag.mode = WK_WAKEUP; + appl_wait_flag.flags = WK_WAKEUP; module_wake_up (&appl_proc); }; } @@ -101,7 +85,7 @@ if (count != sizeof (struct patmgr_info)) { printk ("PATMGR%d: Invalid read count\n", dev); - return -EIO; + return -(EIO); } while (!ok && !current_got_fatal_signal ()) @@ -113,14 +97,14 @@ !current_got_fatal_signal ()) { - server_wait_flag[dev].mode = WK_SLEEP; + server_wait_flag[dev].flags = WK_SLEEP; module_interruptible_sleep_on (&server_procs[dev]); - server_wait_flag[dev].mode &= ~WK_SLEEP;; + server_wait_flag[dev].flags &= ~WK_SLEEP;; } if (mbox[dev] && msg_direction[dev] == A_TO_S) { - memcpy_tofs (&((buf)[0]), (char *) mbox[dev], count); + memcpy_tofs (&(buf)[0], (char *) mbox[dev], count); msg_direction[dev] = 0; ok = 1; } @@ -130,7 +114,7 @@ } if (!ok) - return -EINTR; + return -(EINTR); return count; } @@ -142,10 +126,10 @@ if (count < 4) { printk ("PATMGR%d: Write count < 4\n", dev); - return -EIO; + return -(EIO); } - memcpy_fromfs ((char *) mbox[dev], &((buf)[0]), 4); + memcpy_fromfs ((char *) mbox[dev], &(buf)[0], 4); if (*(unsigned char *) mbox[dev] == SEQ_FULLSIZE) { @@ -153,7 +137,7 @@ tmp_dev = ((unsigned short *) mbox[dev])[2]; if (tmp_dev != dev) - return -ENXIO; + return -(ENXIO); return synth_devs[dev]->load_patch (dev, *(unsigned short *) mbox[dev], buf, 4, count, 1); @@ -162,7 +146,7 @@ if (count != sizeof (struct patmgr_info)) { printk ("PATMGR%d: Invalid write count\n", dev); - return -EIO; + return -(EIO); } /* @@ -175,13 +159,13 @@ if (mbox[dev] && !msg_direction[dev]) { - memcpy_fromfs (&((char *) mbox[dev])[4], &((buf)[4]), count - 4); + memcpy_fromfs (&((char *) mbox[dev])[4], &(buf)[4], count - 4); msg_direction[dev] = S_TO_A; - if ((appl_wait_flag.mode & WK_SLEEP)) + if ((appl_wait_flag.flags & WK_SLEEP)) { { - appl_wait_flag.mode = WK_WAKEUP; + appl_wait_flag.flags = WK_WAKEUP; module_wake_up (&appl_proc); }; } @@ -209,23 +193,23 @@ mbox[dev] = rec; msg_direction[dev] = A_TO_S; - if ((server_wait_flag[dev].mode & WK_SLEEP)) + if ((server_wait_flag[dev].flags & WK_SLEEP)) { { - server_wait_flag[dev].mode = WK_WAKEUP; + server_wait_flag[dev].flags = WK_WAKEUP; module_wake_up (&server_procs[dev]); }; } - appl_wait_flag.mode = WK_SLEEP; + appl_wait_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&appl_proc); - appl_wait_flag.mode &= ~WK_SLEEP;; + appl_wait_flag.flags &= ~WK_SLEEP;; if (msg_direction[dev] != S_TO_A) { rec->key = PM_ERROR; - rec->parm1 = -EIO; + rec->parm1 = -(EIO); } else if (rec->key == PM_ERROR) { @@ -255,7 +239,7 @@ if (!pmgr_opened[dev]) return 0; - tmp_mbox = (struct patmgr_info *) kmalloc (sizeof (struct patmgr_info), GFP_KERNEL); + tmp_mbox = (struct patmgr_info *) vmalloc (sizeof (struct patmgr_info)); if (tmp_mbox == NULL) { @@ -279,24 +263,24 @@ mbox[dev]->parm3 = p3; msg_direction[dev] = A_TO_S; - if ((server_wait_flag[dev].mode & WK_SLEEP)) + if ((server_wait_flag[dev].flags & WK_SLEEP)) { { - server_wait_flag[dev].mode = WK_WAKEUP; + server_wait_flag[dev].flags = WK_WAKEUP; module_wake_up (&server_procs[dev]); }; } - appl_wait_flag.mode = WK_SLEEP; + appl_wait_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&appl_proc); - appl_wait_flag.mode &= ~WK_SLEEP;; + appl_wait_flag.flags &= ~WK_SLEEP;; mbox[dev] = NULL; msg_direction[dev] = 0; } restore_flags (flags); - kfree (tmp_mbox); + vfree (tmp_mbox); return err; } diff -ur --new-file old/linux/drivers/sound/pss.c new/linux/drivers/sound/pss.c --- old/linux/drivers/sound/pss.c Sat Jun 1 08:41:05 1996 +++ new/linux/drivers/sound/pss.c Tue Jul 23 09:26:53 1996 @@ -4,27 +4,11 @@ * The low level driver for the Personal Sound System (ECHO ESC614). */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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 @@ -69,12 +53,12 @@ #include "synth-ld.h" #else static int pss_synthLen = 0; -static unsigned char pss_synth[1] = -{0}; +static unsigned char *pss_synth = +NULL; #endif -typedef struct pss_config +typedef struct pss_confdata { int base; int irq; @@ -82,10 +66,10 @@ int *osp; } -pss_config; +pss_confdata; -static pss_config pss_data; -static pss_config *devc = &pss_data; +static pss_confdata pss_data; +static pss_confdata *devc = &pss_data; static int pss_initialized = 0; static int nonstandard_microcode = 0; @@ -122,7 +106,7 @@ } static int -set_irq (pss_config * devc, int dev, int irq) +set_irq (pss_confdata * devc, int dev, int irq) { static unsigned short irq_bits[16] = { @@ -150,7 +134,7 @@ } static int -set_io_base (pss_config * devc, int dev, int base) +set_io_base (pss_confdata * devc, int dev, int base) { unsigned short tmp = inw (REG (dev)) & 0x003f; unsigned short bits = (base & 0x0ffc) << 4; @@ -161,7 +145,7 @@ } static int -set_dma (pss_config * devc, int dev, int dma) +set_dma (pss_confdata * devc, int dev, int dma) { static unsigned short dma_bits[8] = { @@ -187,7 +171,7 @@ } static int -pss_reset_dsp (pss_config * devc) +pss_reset_dsp (pss_confdata * devc) { unsigned long i, limit = jiffies + 10; @@ -202,7 +186,7 @@ } static int -pss_put_dspword (pss_config * devc, unsigned short word) +pss_put_dspword (pss_confdata * devc, unsigned short word) { int i, val; @@ -219,7 +203,7 @@ } static int -pss_get_dspword (pss_config * devc, unsigned short *word) +pss_get_dspword (pss_confdata * devc, unsigned short *word) { int i, val; @@ -237,7 +221,7 @@ } static int -pss_download_boot (pss_config * devc, unsigned char *block, int size, int flags) +pss_download_boot (pss_confdata * devc, unsigned char *block, int size, int flags) { int i, limit, val, count; @@ -276,7 +260,7 @@ break; else { - printk ("\nPSS: DownLoad timeout problems, byte %d=%d\n", + printk ("\nPSS: Download timeout problems, byte %d=%d\n", count, size); return 0; } @@ -320,8 +304,8 @@ return 1; } -long -attach_pss (long mem_start, struct address_info *hw_config) +void +attach_pss (struct address_info *hw_config) { unsigned short id; char tmp[100]; @@ -332,7 +316,7 @@ devc->osp = hw_config->osp; if (!probe_pss (hw_config)) - return mem_start; + return; id = inw (REG (PSS_ID)) & 0x00ff; @@ -349,27 +333,25 @@ if (sound_alloc_dma (hw_config->dma, "PSS")) { printk ("pss.c: Can't allocate DMA channel\n"); - return mem_start; + return; } if (!set_irq (devc, CONF_PSS, devc->irq)) { printk ("PSS: IRQ error\n"); - return mem_start; + return; } if (!set_dma (devc, CONF_PSS, devc->dma)) { printk ("PSS: DRQ error\n"); - return mem_start; + return; } #endif pss_initialized = 1; sprintf (tmp, "ECHO-PSS Rev. %d", id); conf_printf (tmp, hw_config); - - return mem_start; } int @@ -440,14 +422,14 @@ if (pss_synthLen == 0) { printk ("PSS: MIDI synth microcode not available.\n"); - return -EIO; + return -(EIO); } if (nonstandard_microcode) if (!pss_download_boot (devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) { printk ("PSS: Unable to load MIDI synth microcode to DSP.\n"); - return -EIO; + return -(EIO); } nonstandard_microcode = 0; break; @@ -478,12 +460,12 @@ download_boot_block (void *dev_info, copr_buffer * buf) { if (buf->len <= 0 || buf->len > sizeof (buf->data)) - return -EINVAL; + return -(EINVAL); if (!pss_download_boot (devc, buf->data, buf->len, buf->flags)) { printk ("PSS: Unable to load microcode block to DSP.\n"); - return -EIO; + return -(EIO); } nonstandard_microcode = 1; /* The MIDI microcode has been overwritten */ @@ -507,31 +489,29 @@ copr_buffer *buf; int err; - buf = (copr_buffer *) kmalloc (sizeof (copr_buffer), GFP_KERNEL); + buf = (copr_buffer *) vmalloc (sizeof (copr_buffer)); if (buf == NULL) - return -ENOSPC; + return -(ENOSPC); - memcpy_fromfs ((char *) buf, &(((char *) arg)[0]), sizeof (*buf)); + memcpy_fromfs ((char *) buf, &((char *) arg)[0], sizeof (*buf)); err = download_boot_block (dev_info, buf); - kfree (buf); + vfree (buf); return err; } break; case SNDCTL_COPR_SENDMSG: { - /* send buf->len words from buf->data to DSP */ - copr_msg *buf; unsigned long flags; unsigned short *data; int i; - buf = (copr_msg *) kmalloc (sizeof (copr_msg), GFP_KERNEL); + buf = (copr_msg *) vmalloc (sizeof (copr_msg)); if (buf == NULL) - return -ENOSPC; + return -(ENOSPC); - memcpy_fromfs ((char *) buf, &(((char *) arg)[0]), sizeof (*buf)); + memcpy_fromfs ((char *) buf, &((char *) arg)[0], sizeof (*buf)); data = (unsigned short *) (buf->data); @@ -543,16 +523,15 @@ if (!pss_put_dspword (devc, *data++)) { restore_flags (flags); - /* feed back number of WORDs sent */ - memcpy_tofs( (char *)(&(((copr_msg *)arg)->len)), - (char *)(&i), sizeof(buf->len)); - kfree (buf); - return -EIO; + buf->len = i; /* feed back number of WORDs sent */ + memcpy_tofs (&((char *) arg)[0], &buf, sizeof (buf)); + vfree (buf); + return -(EIO); } } restore_flags (flags); - kfree (buf); + vfree (buf); return 0; } @@ -561,42 +540,37 @@ case SNDCTL_COPR_RCVMSG: { - /* try to read as much words as possible from DSP into buf */ copr_msg *buf; unsigned long flags; unsigned short *data; unsigned int i; int err = 0; - buf = (copr_msg *) kmalloc (sizeof (copr_msg), GFP_KERNEL); + buf = (copr_msg *) vmalloc (sizeof (copr_msg)); if (buf == NULL) - return -ENOSPC; -#if 0 - memcpy_fromfs ((char *) buf, &(((char *) arg)[0]), sizeof (*buf)); -#endif + return -(ENOSPC); + data = (unsigned short *) buf->data; save_flags (flags); cli (); - for (i = 0; i < sizeof(buf->data); i++) + for (i = 0; i < buf->len; i++) { + buf->len = i; /* feed back number of WORDs read */ if (!pss_get_dspword (devc, data++)) { - buf->len = i; /* feed back number of WORDs read */ - err = (i==0)? -EIO : 0; /* EIO only if no word read */ + if (i == 0) + err = -(EIO); break; } } - if( i==sizeof(buf->data) ) - buf->len = i; - restore_flags (flags); - memcpy_tofs ((&((char *) arg)[0]), buf, sizeof (*buf)); - kfree (buf); + memcpy_tofs (&((char *) arg)[0], &buf, sizeof (buf)); + vfree (buf); return err; } @@ -609,32 +583,32 @@ unsigned long flags; unsigned short tmp; - memcpy_fromfs ((char *) &buf, &(((char *) arg)[0]), sizeof (buf)); + memcpy_fromfs ((char *) &buf, &((char *) arg)[0], sizeof (buf)); save_flags (flags); cli (); if (!pss_put_dspword (devc, 0x00d0)) { restore_flags (flags); - return -EIO; + return -(EIO); } if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff))) { restore_flags (flags); - return -EIO; + return -(EIO); } if (!pss_get_dspword (devc, &tmp)) { restore_flags (flags); - return -EIO; + return -(EIO); } buf.parm1 = tmp; restore_flags (flags); - memcpy_tofs ((&((char *) arg)[0]), &buf, sizeof (buf)); + memcpy_tofs (&((char *) arg)[0], &buf, sizeof (buf)); return 0; } break; @@ -645,27 +619,27 @@ unsigned long flags; unsigned short tmp; - memcpy_fromfs ((char *) &buf, &(((char *) arg)[0]), sizeof (buf)); + memcpy_fromfs ((char *) &buf, &((char *) arg)[0], sizeof (buf)); save_flags (flags); cli (); if (!pss_put_dspword (devc, 0x00d1)) { restore_flags (flags); - return -EIO; + return -(EIO); } if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff))) { restore_flags (flags); - return -EIO; + return -(EIO); } tmp = (unsigned int) buf.parm2 & 0xffff; if (!pss_put_dspword (devc, tmp)) { restore_flags (flags); - return -EIO; + return -(EIO); } restore_flags (flags); @@ -679,34 +653,34 @@ unsigned long flags; unsigned short tmp; - memcpy_fromfs ((char *) &buf, &(((char *) arg)[0]), sizeof (buf)); + memcpy_fromfs ((char *) &buf, &((char *) arg)[0], sizeof (buf)); save_flags (flags); cli (); if (!pss_put_dspword (devc, 0x00d3)) { restore_flags (flags); - return -EIO; + return -(EIO); } if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff))) { restore_flags (flags); - return -EIO; + return -(EIO); } tmp = (unsigned int) buf.parm2 & 0x00ff; if (!pss_put_dspword (devc, tmp)) { restore_flags (flags); - return -EIO; + return -(EIO); } tmp = ((unsigned int) buf.parm2 >> 8) & 0xffff; if (!pss_put_dspword (devc, tmp)) { restore_flags (flags); - return -EIO; + return -(EIO); } restore_flags (flags); @@ -720,50 +694,50 @@ unsigned long flags; unsigned short tmp; - memcpy_fromfs ((char *) &buf, &(((char *) arg)[0]), sizeof (buf)); + memcpy_fromfs ((char *) &buf, &((char *) arg)[0], sizeof (buf)); save_flags (flags); cli (); if (!pss_put_dspword (devc, 0x00d2)) { restore_flags (flags); - return -EIO; + return -(EIO); } if (!pss_put_dspword (devc, (unsigned short) (buf.parm1 & 0xffff))) { restore_flags (flags); - return -EIO; + return -(EIO); } - if (!pss_get_dspword (devc, &tmp)) /* Read msb */ + if (!pss_get_dspword (devc, &tmp)) /* Read MSB */ { restore_flags (flags); - return -EIO; + return -(EIO); } buf.parm1 = tmp << 8; - if (!pss_get_dspword (devc, &tmp)) /* Read lsb */ + if (!pss_get_dspword (devc, &tmp)) /* Read LSB */ { restore_flags (flags); - return -EIO; + return -(EIO); } buf.parm1 |= tmp & 0x00ff; restore_flags (flags); - memcpy_tofs ((&((char *) arg)[0]), &buf, sizeof (buf)); + memcpy_tofs (&((char *) arg)[0], &buf, sizeof (buf)); return 0; } break; default: - return -EINVAL; + return -(EINVAL); } - return -EINVAL; + return -(EINVAL); } static coproc_operations pss_coproc_operations = @@ -776,23 +750,19 @@ &pss_data }; -long -attach_pss_mpu (long mem_start, struct address_info *hw_config) +void +attach_pss_mpu (struct address_info *hw_config) { #if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) - long ret; - { int prev_devs; + prev_devs = num_midis; - ret = attach_mpu401 (mem_start, hw_config); + attach_mpu401 (hw_config); if (num_midis == (prev_devs + 1)) /* The MPU driver installed itself */ midi_devs[prev_devs]->coproc = &pss_coproc_operations; } - return ret; -#else - return mem_start; #endif } @@ -842,19 +812,16 @@ return probe_ms_sound (hw_config); } -long -attach_pss_mss (long mem_start, struct address_info *hw_config) +void +attach_pss_mss (struct address_info *hw_config) { int prev_devs; - long ret; prev_devs = num_audiodevs; - ret = attach_ms_sound (mem_start, hw_config); + attach_ms_sound (hw_config); if (num_audiodevs == (prev_devs + 1)) /* The MSS driver installed itself */ audio_devs[prev_devs]->coproc = &pss_coproc_operations; - - return ret; } void diff -ur --new-file old/linux/drivers/sound/sb.h new/linux/drivers/sound/sb.h --- old/linux/drivers/sound/sb.h Sun Mar 24 21:49:43 1996 +++ new/linux/drivers/sound/sb.h Sun Jul 7 19:08:16 1996 @@ -1,15 +1,15 @@ -#define DSP_RESET (sbc_base + 0x6) -#define DSP_READ (sbc_base + 0xA) -#define DSP_WRITE (sbc_base + 0xC) -#define DSP_COMMAND (sbc_base + 0xC) -#define DSP_STATUS (sbc_base + 0xC) -#define DSP_DATA_AVAIL (sbc_base + 0xE) -#define DSP_DATA_AVL16 (sbc_base + 0xF) -#define MIXER_ADDR (sbc_base + 0x4) -#define MIXER_DATA (sbc_base + 0x5) -#define OPL3_LEFT (sbc_base + 0x0) -#define OPL3_RIGHT (sbc_base + 0x2) -#define OPL3_BOTH (sbc_base + 0x8) +#define DSP_RESET (devc->base + 0x6) +#define DSP_READ (devc->base + 0xA) +#define DSP_WRITE (devc->base + 0xC) +#define DSP_COMMAND (devc->base + 0xC) +#define DSP_STATUS (devc->base + 0xC) +#define DSP_DATA_AVAIL (devc->base + 0xE) +#define DSP_DATA_AVL16 (devc->base + 0xF) +#define MIXER_ADDR (devc->base + 0x4) +#define MIXER_DATA (devc->base + 0x5) +#define OPL3_LEFT (devc->base + 0x0) +#define OPL3_RIGHT (devc->base + 0x2) +#define OPL3_BOTH (devc->base + 0x8) /* DSP Commands */ #define DSP_CMD_SPKON 0xD1 @@ -26,3 +26,96 @@ #define NORMAL_MIDI 0 #define UART_MIDI 1 + +/* + * Device models + */ +#define MDL_NONE 0 +#define MDL_SB1 1 /* SB1.0 or 1.5 */ +#define MDL_SB2 2 /* SB2.0 */ +#define MDL_SB201 3 /* SB2.01 */ +#define MDL_SBPRO 4 /* SB Pro */ +#define MDL_SB16 5 /* SB16/32/AWE */ +#define MDL_JAZZ 10 /* Media Vision Jazz16 */ +#define MDL_SMW 11 /* Logitech SoundMan Wave (Jazz16) */ +#define MDL_ESS 12 /* ESS ES688 and ES1688 */ +#define MDL_AZTECH 13 /* Aztech Sound Galaxy family */ + +/* + * Config flags + */ +#define SB_NO_MIDI 0x00000001 +#define SB_NO_MIXER 0x00000002 +#define SB_NO_AUDIO 0x00000004 +#define SB_NO_RECORDING 0x00000008 /* No audio recording */ +#define SB_MIDI_ONLY (SB_NO_AUDIO|SB_NO_MIXER) + +struct mixer_def { + unsigned int regno: 8; + unsigned int bitoffs:4; + unsigned int nbits:4; +}; + +typedef struct mixer_def mixer_tab[32][2]; +typedef struct mixer_def mixer_ent; + +typedef struct sb_devc { + int dev; + + /* Hardware parameters */ + int *osp; + int minor, major; + int type; + int model, submodel; + int caps; +# define SBCAP_STEREO 0x00000001 +# define SBCAP_16BITS 0x00000002 + + /* Hardware resources */ + int base; + int irq; + int dma8, dma16; + + /* State variables */ + int opened; + int speed, bits, channels; + volatile int irq_ok; + volatile int intr_active, irq_mode; + + /* Mixer fields */ + unsigned short levels[SOUND_MIXER_NRDEVICES]; + mixer_tab *iomap; + int mixer_caps, recmask, supported_devices; + int supported_rec_devices; + int my_mixerdev; + + /* Audio fields */ + unsigned long trg_buf; + int trigger_bits; + int trg_bytes; + int trg_intrflag; + int trg_restart; + unsigned char tconst; + int my_dev; + + /* MIDI fields */ + int my_mididev; + int input_opened; + void (*midi_input_intr) (int dev, unsigned char data); + } sb_devc; + +int sb_dsp_command (sb_devc *devc, unsigned char val); +int sb_dsp_get_byte (sb_devc *devc); +int sb_dsp_reset (sb_devc *devc); +void sb_setmixer (sb_devc *devc, unsigned int port, unsigned int value); +unsigned int sb_getmixer (sb_devc *devc, unsigned int port); +int sb_dsp_detect (struct address_info *hw_config); +void sb_dsp_init (struct address_info *hw_config); +void sb_dsp_unload(struct address_info *hw_config); +int sb_mixer_init(sb_devc *devc); +void smw_mixer_init(sb_devc *devc); +void sb_dsp_midi_init (sb_devc *devc); +void sb_audio_init (sb_devc *devc, char *name); +void sb_midi_interrupt (sb_devc *devc); +int ess_write (sb_devc *devc, unsigned char reg, unsigned char data); +int ess_read (sb_devc *devc, unsigned char reg); diff -ur --new-file old/linux/drivers/sound/sb16_dsp.c new/linux/drivers/sound/sb16_dsp.c --- old/linux/drivers/sound/sb16_dsp.c Mon Mar 25 08:25:26 1996 +++ new/linux/drivers/sound/sb16_dsp.c Thu Jan 1 01:00:00 1970 @@ -1,643 +0,0 @@ -/* - * sound/sb16_dsp.c - * - * The low level driver for the SoundBlaster DSP chip. - */ -/* - * Copyright by Hannu Savolainen 1993-1996 - * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include - - -#define DEB(x) -#define DEB1(x) -/* - * #define DEB_DMARES - */ -#include "sound_config.h" -#include "sb.h" -#include "sb_mixer.h" - -#if defined(CONFIG_SB) && defined(CONFIG_AUDIO) - -extern int sbc_base; -extern int *sb_osp; - -static int sb16_dsp_ok = 0; -static int dsp_16bit = 0; -static int dsp_stereo = 0; -static int dsp_current_speed = 8000; -static int dsp_busy = 0; -static int dma16 = -1, dma8 = -1; -static int trigger_bits = 0; -static unsigned long dsp_count = 0; - -static int irq_mode = IMODE_NONE; -static int my_dev = 0; - -static volatile int intr_active = 0; - -static int sb16_dsp_open (int dev, int mode); -static void sb16_dsp_close (int dev); -static void sb16_dsp_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart); -static void sb16_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart); -static int sb16_dsp_ioctl (int dev, unsigned int cmd, caddr_t arg, int local); -static int sb16_dsp_prepare_for_input (int dev, int bsize, int bcount); -static int sb16_dsp_prepare_for_output (int dev, int bsize, int bcount); -static void sb16_dsp_reset (int dev); -static void sb16_dsp_halt (int dev); -static void sb16_dsp_trigger (int dev, int bits); -static int dsp_set_speed (int); -static int dsp_set_stereo (int); -static void dsp_cleanup (void); -int sb_reset_dsp (void); - -static struct audio_operations sb16_dsp_operations = -{ - "SoundBlaster 16", - DMA_AUTOMODE, - AFMT_U8 | AFMT_S16_LE, - NULL, - sb16_dsp_open, - sb16_dsp_close, - sb16_dsp_output_block, - sb16_dsp_start_input, - sb16_dsp_ioctl, - sb16_dsp_prepare_for_input, - sb16_dsp_prepare_for_output, - sb16_dsp_reset, - sb16_dsp_halt, - NULL, - NULL, - NULL, - NULL, - sb16_dsp_trigger -}; - -static int -sb_dsp_command01 (unsigned char val) -{ - int i = 1 << 16; - - while (--i & (!inb (DSP_STATUS) & 0x80)); - if (!i) - printk ("SB16 sb_dsp_command01 Timeout\n"); - return sb_dsp_command (val); -} - -static int -dsp_set_speed (int mode) -{ - DEB (printk ("dsp_set_speed(%d)\n", mode)); - if (mode) - { - if (mode < 5000) - mode = 5000; - if (mode > 44100) - mode = 44100; - dsp_current_speed = mode; - } - return mode; -} - -static int -dsp_set_stereo (int mode) -{ - DEB (printk ("dsp_set_stereo(%d)\n", mode)); - - dsp_stereo = mode; - - return mode; -} - -static int -dsp_set_bits (int arg) -{ - DEB (printk ("dsp_set_bits(%d)\n", arg)); - - if (arg) - switch (arg) - { - case 8: - dsp_16bit = 0; - break; - case 16: - dsp_16bit = 1; - break; - default: - dsp_16bit = 0; - } - return dsp_16bit ? 16 : 8; -} - -static int -sb16_dsp_ioctl (int dev, unsigned int cmd, caddr_t arg, int local) -{ - switch (cmd) - { - case SOUND_PCM_WRITE_RATE: - if (local) - return dsp_set_speed ((long) arg); - return snd_ioctl_return ((int *) arg, dsp_set_speed (get_fs_long ((long *) arg))); - - case SOUND_PCM_READ_RATE: - if (local) - return dsp_current_speed; - return snd_ioctl_return ((int *) arg, dsp_current_speed); - - case SNDCTL_DSP_STEREO: - if (local) - return dsp_set_stereo ((long) arg); - return snd_ioctl_return ((int *) arg, dsp_set_stereo (get_fs_long ((long *) arg))); - - case SOUND_PCM_WRITE_CHANNELS: - if (local) - return dsp_set_stereo ((long) arg - 1) + 1; - return snd_ioctl_return ((int *) arg, dsp_set_stereo (get_fs_long ((long *) arg) - 1) + 1); - - case SOUND_PCM_READ_CHANNELS: - if (local) - return dsp_stereo + 1; - return snd_ioctl_return ((int *) arg, dsp_stereo + 1); - - case SNDCTL_DSP_SETFMT: - if (local) - return dsp_set_bits ((long) arg); - return snd_ioctl_return ((int *) arg, dsp_set_bits (get_fs_long ((long *) arg))); - - case SOUND_PCM_READ_BITS: - if (local) - return dsp_16bit ? 16 : 8; - return snd_ioctl_return ((int *) arg, dsp_16bit ? 16 : 8); - - case SOUND_PCM_WRITE_FILTER: /* - * NOT YET IMPLEMENTED - */ - if (get_fs_long ((long *) arg) > 1) - return snd_ioctl_return ((int *) arg, -EINVAL); - default: - return -EINVAL; - } - - return -EINVAL; -} - -static int -sb16_dsp_open (int dev, int mode) -{ - int retval; - - DEB (printk ("sb16_dsp_open()\n")); - if (!sb16_dsp_ok) - { - printk ("SB16 Error: SoundBlaster board not installed\n"); - return -ENXIO; - } - - if (intr_active) - return -EBUSY; - - retval = sb_get_irq (); - if (retval < 0) - return retval; - - sb_reset_dsp (); - - if (dma16 != dma8) - if (sound_open_dma (dma16, "SB16 (16bit)")) - { - printk ("SB16: Unable to grab DMA%d\n", dma16); - sb_free_irq (); - return -EBUSY; - } - - irq_mode = IMODE_NONE; - dsp_busy = 1; - trigger_bits = 0; - - return 0; -} - -static void -sb16_dsp_close (int dev) -{ - unsigned long flags; - - DEB (printk ("sb16_dsp_close()\n")); - sb_dsp_command01 (0xd9); - sb_dsp_command01 (0xd5); - sb_reset_dsp (); - - save_flags (flags); - cli (); - - audio_devs[dev]->dmachan1 = audio_devs[dev]->dmachan2 = dma8; - - if (dma16 != dma8) - sound_close_dma (dma16); - sb_free_irq (); - dsp_cleanup (); - dsp_busy = 0; - restore_flags (flags); -} - -static unsigned long trg_buf; -static int trg_bytes; -static int trg_intrflag; -static int trg_restart; - -static void -sb16_dsp_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart) -{ - trg_buf = buf; - trg_bytes = count; - trg_intrflag = intrflag; - trg_restart = dma_restart; - irq_mode = IMODE_OUTPUT; -} - -static void -actually_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart) -{ - unsigned long flags, cnt; - - cnt = count; - if (dsp_16bit) - cnt >>= 1; - cnt--; - - if (audio_devs[dev]->flags & DMA_AUTOMODE && - intrflag && - cnt == dsp_count) - { - irq_mode = IMODE_OUTPUT; - intr_active = 1; - return; /* - * Auto mode on. No need to react - */ - } - save_flags (flags); - cli (); - - if (dma_restart) - { - sb16_dsp_halt (dev); - DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); - } - sb_dsp_command (0x41); - sb_dsp_command ((unsigned char) ((dsp_current_speed >> 8) & 0xff)); - sb_dsp_command ((unsigned char) (dsp_current_speed & 0xff)); - sb_dsp_command ((unsigned char) (dsp_16bit ? 0xb6 : 0xc6)); - dsp_count = cnt; - sb_dsp_command ((unsigned char) ((dsp_stereo ? 0x20 : 0) + - (dsp_16bit ? 0x10 : 0))); - sb_dsp_command01 ((unsigned char) (cnt & 0xff)); - sb_dsp_command ((unsigned char) (cnt >> 8)); - - irq_mode = IMODE_OUTPUT; - intr_active = 1; - restore_flags (flags); -} - -static void -sb16_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart) -{ - trg_buf = buf; - trg_bytes = count; - trg_intrflag = intrflag; - trg_restart = dma_restart; - irq_mode = IMODE_INPUT; -} - -static void -actually_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart) -{ - unsigned long flags, cnt; - - cnt = count; - if (dsp_16bit) - cnt >>= 1; - cnt--; - - if (audio_devs[dev]->flags & DMA_AUTOMODE && - intrflag && - cnt == dsp_count) - { - irq_mode = IMODE_INPUT; - intr_active = 1; - return; /* - * Auto mode on. No need to react - */ - } - save_flags (flags); - cli (); - - if (dma_restart) - { - sb16_dsp_halt (dev); - DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); - } - - sb_dsp_command (0x42); - sb_dsp_command ((unsigned char) ((dsp_current_speed >> 8) & 0xff)); - sb_dsp_command ((unsigned char) (dsp_current_speed & 0xff)); - - sb_dsp_command ((unsigned char) (dsp_16bit ? 0xbe : 0xce)); - dsp_count = cnt; - sb_dsp_command ((unsigned char) ((dsp_stereo ? 0x20 : 0) + - (dsp_16bit ? 0x10 : 0))); - sb_dsp_command01 ((unsigned char) (cnt & 0xff)); - sb_dsp_command ((unsigned char) (cnt >> 8)); - - irq_mode = IMODE_INPUT; - intr_active = 1; - restore_flags (flags); -} - -static int -sb16_dsp_prepare_for_input (int dev, int bsize, int bcount) -{ - audio_devs[my_dev]->dmachan1 = - audio_devs[my_dev]->dmachan2 = - dsp_16bit ? dma16 : dma8; - dsp_count = 0; - dsp_cleanup (); - trigger_bits = 0; - return 0; -} - -static int -sb16_dsp_prepare_for_output (int dev, int bsize, int bcount) -{ - audio_devs[my_dev]->dmachan1 = - audio_devs[my_dev]->dmachan2 = - dsp_16bit ? dma16 : dma8; - dsp_count = 0; - dsp_cleanup (); - trigger_bits = 0; - return 0; -} - -static void -sb16_dsp_trigger (int dev, int bits) -{ - trigger_bits = bits; - - if (!bits) - { - sb_dsp_command (0xd0); /* Halt DMA */ - } - else if (bits & irq_mode) - switch (irq_mode) - { - case IMODE_INPUT: - actually_start_input (my_dev, trg_buf, trg_bytes, - trg_intrflag, trg_restart); - - break; - - case IMODE_OUTPUT: - actually_output_block (my_dev, trg_buf, trg_bytes, - trg_intrflag, trg_restart); - break; - - } -} - -static void -dsp_cleanup (void) -{ - irq_mode = IMODE_NONE; - intr_active = 0; -} - -static void -sb16_dsp_reset (int dev) -{ - unsigned long flags; - - save_flags (flags); - cli (); - - sb_reset_dsp (); - dsp_cleanup (); - - restore_flags (flags); -} - -static void -sb16_dsp_halt (int dev) -{ - if (dsp_16bit) - { - sb_dsp_command01 (0xd9); - sb_dsp_command01 (0xd5); - } - else - { - sb_dsp_command01 (0xda); - sb_dsp_command01 (0xd0); - } - /* DMAbuf_reset_dma (dev); */ -} - -static void -set_irq_hw (int level) -{ - int ival; - - switch (level) - { - case 5: - ival = 2; - break; - case 7: - ival = 4; - break; - case 9: - ival = 1; - break; - case 10: - ival = 8; - break; - default: - printk ("SB16_IRQ_LEVEL %d does not exist\n", level); - return; - } - sb_setmixer (IRQ_NR, ival); -} - -long -sb16_dsp_init (long mem_start, struct address_info *hw_config) -{ - extern int sbc_major, sbc_minor; - - if (sbc_major < 4) - return mem_start; /* Not a SB16 */ - - sprintf (sb16_dsp_operations.name, "SoundBlaster 16 %d.%d", sbc_major, sbc_minor); - - conf_printf (sb16_dsp_operations.name, hw_config); - - if (num_audiodevs < MAX_AUDIO_DEV) - { - audio_devs[my_dev = num_audiodevs++] = &sb16_dsp_operations; - audio_devs[my_dev]->dmachan1 = audio_devs[my_dev]->dmachan2 = dma8; - audio_devs[my_dev]->buffsize = DSP_BUFFSIZE; - - if (sound_alloc_dma (dma8, "SB16 (8bit)")) - { - printk ("SB16: Unable to grab DMA%d\n", dma8); - } - - if (dma16 != dma8) - if (sound_alloc_dma (dma16, "SB16 (16bit)")) - { - printk ("SB16: Unable to grab DMA%d\n", dma16); - } - } - else - printk ("SB: Too many DSP devices available\n"); - sb16_dsp_ok = 1; - return mem_start; -} - -static void -set_dma (int dma) -{ - if (dma >= 0 && dma < 4) - dma8 = dma; - if (dma >= 5 && dma <= 7) - dma16 = dma; -} - -int -sb16_dsp_detect (struct address_info *hw_config) -{ - struct address_info *sb_config; - extern int sbc_major, Jazz16_detected; - - extern void Jazz16_set_dma16 (int dma); - int irq; - - if (sb16_dsp_ok) - { - return 1; /* Can't drive two cards */ - } - - irq = hw_config->irq; - set_dma (hw_config->dma); - set_dma (hw_config->dma2); - - if (Jazz16_detected) - { - Jazz16_set_dma16 (dma16); - sb16_dsp_ok = 1; - return 1; - } - - if (dma8 == -1) - if (!(sb_config = sound_getconf (SNDCARD_SB))) - { - printk ("SB16 Error: Plain SB not configured\n"); - return 0; - } - else - { - dma8 = sb_config->dma; - irq = sb_config->irq; - } - - if (dma16 == -1) - dma16 = dma8; - - /* - * sb_setmixer(OPSW,0xf); if(sb_getmixer(OPSW)!=0xf) return 0; - */ - - if (!sb_reset_dsp ()) - return 0; - - if (sbc_major < 4) /* Set by the plain SB driver */ - return 0; /* Not a SB16 */ - - if (dma16 < 4) - if (dma16 != dma8) - { - printk ("SB16 Error: Invalid DMA channel %d/%d\n", - dma8, dma16); - return 0; - } - - set_irq_hw (irq); - sb_setmixer (DMA_NR, (1 << dma16) | (1 << dma8)); - - DEB (printk ("SoundBlaster 16: IRQ %d DMA %d OK\n", sb_config->irq, dma16)); - - /* - * dsp_showmessage(0xe3,99); - */ - sb16_dsp_ok = 1; - return 1; -} - -void -unload_sb16 (struct address_info *hw_config) -{ - extern int Jazz16_detected; - - if (Jazz16_detected) - return; - - sound_free_dma (dma8); - - if (dma16 != dma8) - sound_free_dma (dma16); -} - -void -sb16_dsp_interrupt (int unused) -{ - int data; - - data = inb (DSP_DATA_AVL16); /* - * Interrupt acknowledge - */ - - if (intr_active) - switch (irq_mode) - { - case IMODE_OUTPUT: - DMAbuf_outputintr (my_dev, 1); - break; - - case IMODE_INPUT: - DMAbuf_inputintr (my_dev); - break; - - default: - printk ("SoundBlaster: Unexpected interrupt\n"); - } -} - -#endif diff -ur --new-file old/linux/drivers/sound/sb16_midi.c new/linux/drivers/sound/sb16_midi.c --- old/linux/drivers/sound/sb16_midi.c Sun Mar 24 21:50:18 1996 +++ new/linux/drivers/sound/sb16_midi.c Thu Jan 1 01:00:00 1970 @@ -1,364 +0,0 @@ -/* - * sound/sb16_midi.c - * - * The low level driver for the MPU-401 UART emulation of the SB16. - */ -/* - * Copyright by Hannu Savolainen 1993-1996 - * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include - - -#include "sound_config.h" - -#if defined(CONFIG_SB) && defined(CONFIG_MIDI) - -#include "sb.h" - -#define DATAPORT (sb16midi_base) -#define COMDPORT (sb16midi_base+1) -#define STATPORT (sb16midi_base+1) - -extern int *sb_osp; -static int sb16midi_base = 0; - -static int -sb16midi_status (void) -{ - return inb (STATPORT); -} -#define input_avail() (!(sb16midi_status()&INPUT_AVAIL)) -#define output_ready() (!(sb16midi_status()&OUTPUT_READY)) -static void -sb16midi_cmd (unsigned char cmd) -{ - outb (cmd, COMDPORT); -} -static int -sb16midi_read (void) -{ - return inb (DATAPORT); -} -static void -sb16midi_write (unsigned char byte) -{ - outb (byte, DATAPORT); -} - -#define OUTPUT_READY 0x40 -#define INPUT_AVAIL 0x80 -#define MPU_ACK 0xFE -#define MPU_RESET 0xFF -#define UART_MODE_ON 0x3F - -static int sb16midi_opened = 0; -static int sb16midi_detected = 0; -static int my_dev; -extern int sbc_base; - -extern int Jazz16_detected; -extern int AudioDrive; - -static int reset_sb16midi (void); -static void (*midi_input_intr) (int dev, unsigned char data); -static volatile unsigned char input_byte; - -static void -sb16midi_input_loop (void) -{ - while (input_avail ()) - { - unsigned char c = sb16midi_read (); - - if (c == MPU_ACK) - input_byte = c; - else if (sb16midi_opened & OPEN_READ && midi_input_intr) - midi_input_intr (my_dev, c); - } -} - -void -sb16midiintr (int unit) -{ - if (sb16midi_base == 0) - return; - - if (input_avail ()) - sb16midi_input_loop (); -} - -void -sbmidiintr (int irq, void *dev_id, struct pt_regs *dummy) -{ - if (input_avail ()) - sb16midi_input_loop (); -} - -static int -sb16midi_open (int dev, int mode, - void (*input) (int dev, unsigned char data), - void (*output) (int dev) -) -{ - if (sb16midi_opened) - { - return -EBUSY; - } - - while (input_avail ()) - sb16midi_read (); - - midi_input_intr = input; - sb16midi_opened = mode; - - return 0; -} - -static void -sb16midi_close (int dev) -{ - sb16midi_opened = 0; -} - -static int -sb16midi_out (int dev, unsigned char midi_byte) -{ - int timeout; - unsigned long flags; - - /* - * Test for input since pending input seems to block the output. - */ - - save_flags (flags); - cli (); - - if (input_avail ()) - sb16midi_input_loop (); - - restore_flags (flags); - - /* - * Sometimes it takes about 13000 loops before the output becomes ready - * (After reset). Normally it takes just about 10 loops. - */ - - for (timeout = 30000; timeout > 0 && !output_ready (); timeout--); /* - * Wait - */ - - if (!output_ready ()) - { - printk ("MPU-401: Timeout\n"); - return 0; - } - - sb16midi_write (midi_byte); - return 1; -} - -static int -sb16midi_start_read (int dev) -{ - return 0; -} - -static int -sb16midi_end_read (int dev) -{ - return 0; -} - -static int -sb16midi_ioctl (int dev, unsigned cmd, caddr_t arg) -{ - return -EINVAL; -} - -static void -sb16midi_kick (int dev) -{ -} - -static int -sb16midi_buffer_status (int dev) -{ - return 0; /* - * No data in buffers - */ -} - -#define MIDI_SYNTH_NAME "SoundBlaster MPU" -#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT -#include "midi_synth.h" - -static struct midi_operations sb16midi_operations = -{ - {"SoundBlaster MPU", 0, 0, SNDCARD_SB16MIDI}, - &std_midi_synth, - {0}, - sb16midi_open, - sb16midi_close, - sb16midi_ioctl, - sb16midi_out, - sb16midi_start_read, - sb16midi_end_read, - sb16midi_kick, - NULL, - sb16midi_buffer_status, - NULL -}; - -static void -enter_uart_mode (void) -{ - int ok, timeout; - unsigned long flags; - - save_flags (flags); - cli (); - for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); - - input_byte = 0; - sb16midi_cmd (UART_MODE_ON); - - ok = 0; - for (timeout = 50000; timeout > 0 && !ok; timeout--) - if (input_byte == MPU_ACK) - ok = 1; - else if (input_avail ()) - if (sb16midi_read () == MPU_ACK) - ok = 1; - - restore_flags (flags); -} - -long -attach_sb16midi (long mem_start, struct address_info *hw_config) -{ - sb16midi_base = hw_config->io_base; - - if (!sb16midi_detected) - return mem_start; - - request_region (hw_config->io_base, 4, "SB MIDI"); - enter_uart_mode (); - - if (num_midis >= MAX_MIDI_DEV) - { - printk ("Sound: Too many midi devices detected\n"); - return mem_start; - } - - conf_printf ("SoundBlaster MPU-401", hw_config); - - std_midi_synth.midi_dev = my_dev = num_midis; - midi_devs[num_midis++] = &sb16midi_operations; - return mem_start; -} - -static int -reset_sb16midi (void) -{ - int ok, timeout, n; - - /* - * Send the RESET command. Try again if no success at the first time. - */ - - ok = 0; - - /*save_flags(flags);cli(); */ - - for (n = 0; n < 2 && !ok; n++) - { - for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /* - * Wait - */ - input_byte = 0; - sb16midi_cmd (MPU_RESET); /* - * Send MPU-401 RESET Command - */ - - /* - * Wait at least 25 msec. This method is not accurate so let's make the - * loop bit longer. Cannot sleep since this is called during boot. - */ - - for (timeout = 50000; timeout > 0 && !ok; timeout--) - if (input_byte == MPU_ACK) /* Interrupt */ - ok = 1; - else if (input_avail ()) - if (sb16midi_read () == MPU_ACK) - ok = 1; - - } - - sb16midi_opened = 0; - if (ok) - sb16midi_input_loop (); /* - * Flush input before enabling interrupts - */ - - /* restore_flags(flags); */ - - return ok; -} - -int -probe_sb16midi (struct address_info *hw_config) -{ - int ok = 0; - extern int sbc_major; - - extern void ess_midi_init (struct address_info *hw_config); - extern void Jazz16_midi_init (struct address_info *hw_config); - - if (check_region (hw_config->io_base, 4)) - return 0; - - if (AudioDrive) - ess_midi_init (hw_config); - else if (Jazz16_detected) - Jazz16_midi_init (hw_config); - else if (sbc_major < 4) - return 0; /* Not a SB16 */ - - sb16midi_base = hw_config->io_base; - - if (sb_get_irq () < 0) - return 0; - - ok = reset_sb16midi (); - - sb16midi_detected = ok; - return ok; -} - -void -unload_sb16midi (struct address_info *hw_config) -{ - release_region (hw_config->io_base, 4); -} - -#endif diff -ur --new-file old/linux/drivers/sound/sb_audio.c new/linux/drivers/sound/sb_audio.c --- old/linux/drivers/sound/sb_audio.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/sound/sb_audio.c Wed Aug 14 09:21:03 1996 @@ -0,0 +1,1202 @@ +/* + * sound/sb_audio.c + * + * Audio routines for Sound Blaster compatible cards. + */ +/* + * Copyright (C) by Hannu Savolainen 1993-1996 + * + * USS/Lite 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 "sound_config.h" + +#if defined(CONFIG_SBDSP) + +#include "sb_mixer.h" +#include "sb.h" + +static int +sb_audio_open (int dev, int mode) +{ + sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags; + + if (devc == NULL) + { + printk ("SB: Incomplete initialization\n"); + return -(ENXIO); + } + + if (devc->caps & SB_NO_RECORDING && mode & OPEN_READ) + { + printk ("SB: Recording is not possible with this device\n"); + return -(EPERM); + } + + save_flags (flags); + cli (); + if (devc->opened) + { + restore_flags (flags); + return -(EBUSY); + } + + if (devc->dma16 != -1 && devc->dma16 != devc->dma8) + { + if (sound_open_dma (devc->dma16, "Sound Blaster 16 bit")) + { + return -(EBUSY); + } + } + devc->opened = mode; + restore_flags (flags); + + devc->irq_mode = IMODE_NONE; + sb_dsp_reset (devc); + + return 0; +} + +static void +sb_audio_close (int dev) +{ + sb_devc *devc = audio_devs[dev]->devc; + + audio_devs[dev]->dmachan1 = + audio_devs[dev]->dmachan2 = + devc->dma8; + + if (devc->dma16 != -1 && devc->dma16 != devc->dma8) + sound_close_dma (devc->dma16); + + devc->opened = 0; +} + +static void +sb_set_output_parms (int dev, unsigned long buf, int nr_bytes, + int intrflag, int restart_dma) +{ + sb_devc *devc = audio_devs[dev]->devc; + + devc->trg_buf = buf; + devc->trg_bytes = nr_bytes; + devc->trg_intrflag = intrflag; + devc->trg_restart = restart_dma; + devc->irq_mode = IMODE_OUTPUT; +} + +static void +sb_set_input_parms (int dev, unsigned long buf, int count, int intrflag, + int restart_dma) +{ + sb_devc *devc = audio_devs[dev]->devc; + + devc->trg_buf = buf; + devc->trg_bytes = count; + devc->trg_intrflag = intrflag; + devc->trg_restart = restart_dma; + devc->irq_mode = IMODE_INPUT; +} + +/* + * SB1.x compatible routines + */ + +static void +sb1_audio_output_block (int dev, unsigned long buf, int nr_bytes, + int intrflag, int restart_dma) +{ + unsigned long flags; + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; + + DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); + + if (audio_devs[dev]->dmachan1 > 3) + count >>= 1; + count--; + + devc->irq_mode = IMODE_OUTPUT; + + save_flags (flags); + cli (); + if (sb_dsp_command (devc, 0x14)) /* 8 bit DAC using DMA */ + { + sb_dsp_command (devc, (unsigned char) (count & 0xff)); + sb_dsp_command (devc, (unsigned char) ((count >> 8) & 0xff)); + } + else + printk ("SB: Unable to start DAC\n"); + restore_flags (flags); + devc->intr_active = 1; +} + +static void +sb1_audio_start_input (int dev, unsigned long buf, int nr_bytes, int intrflag, + int restart_dma) +{ + unsigned long flags; + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; + + /* + * Start a DMA input to the buffer pointed by dmaqtail + */ + + DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); + + if (audio_devs[dev]->dmachan1 > 3) + count >>= 1; + count--; + + devc->irq_mode = IMODE_INPUT; + + save_flags (flags); + cli (); + if (sb_dsp_command (devc, 0x24)) /* 8 bit ADC using DMA */ + { + sb_dsp_command (devc, (unsigned char) (count & 0xff)); + sb_dsp_command (devc, (unsigned char) ((count >> 8) & 0xff)); + } + else + printk ("SB Error: Unable to start ADC\n"); + restore_flags (flags); + + devc->intr_active = 1; +} + +static void +sb1_audio_trigger (int dev, int bits) +{ + sb_devc *devc = audio_devs[dev]->devc; + + bits &= devc->irq_mode; + + if (!bits) + sb_dsp_command (devc, 0xd0); /* Halt DMA */ + else + { + switch (devc->irq_mode) + { + case IMODE_INPUT: + sb1_audio_start_input (dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag, devc->trg_restart); + break; + + case IMODE_OUTPUT: + sb1_audio_output_block (dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag, devc->trg_restart); + break; + } + } + + devc->trigger_bits = bits; +} + +static int +sb1_audio_prepare_for_input (int dev, int bsize, int bcount) +{ + sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags; + + save_flags (flags); + cli (); + if (sb_dsp_command (devc, 0x40)) + sb_dsp_command (devc, devc->tconst); + sb_dsp_command (devc, DSP_CMD_SPKOFF); + restore_flags (flags); + + devc->trigger_bits = 0; + return 0; +} + +static int +sb1_audio_prepare_for_output (int dev, int bsize, int bcount) +{ + sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags; + + save_flags (flags); + cli (); + if (sb_dsp_command (devc, 0x40)) + sb_dsp_command (devc, devc->tconst); + sb_dsp_command (devc, DSP_CMD_SPKON); + restore_flags (flags); + devc->trigger_bits = 0; + return 0; +} + +static int +sb1_audio_set_speed (int dev, int speed) +{ + int max_speed = 23000; + sb_devc *devc = audio_devs[dev]->devc; + int tmp; + + if (devc->opened & OPEN_READ) + max_speed = 13000; + + if (speed > 0) + { + if (speed < 4000) + speed = 4000; + + if (speed > max_speed) + speed = max_speed; + + devc->tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff; + + tmp = 256 - devc->tconst; + speed = (1000000 + tmp / 2) / tmp; + + devc->speed = speed; + } + + return devc->speed; +} + +static short +sb1_audio_set_channels (int dev, short channels) +{ + sb_devc *devc = audio_devs[dev]->devc; + + return devc->channels = 1; +} + +static unsigned int +sb1_audio_set_bits (int dev, unsigned int bits) +{ + sb_devc *devc = audio_devs[dev]->devc; + + return devc->bits = 8; +} + +static void +sb1_audio_halt_xfer (int dev) +{ + sb_devc *devc = audio_devs[dev]->devc; + + sb_dsp_reset (devc); +} + +/* + * SB 2.0 and SB 2.01 compatible routines + */ + +static void +sb20_audio_output_block (int dev, unsigned long buf, int nr_bytes, + int intrflag, int restart_dma) +{ + unsigned long flags; + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; + unsigned char cmd; + + DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); + + if (audio_devs[dev]->dmachan1 > 3) + count >>= 1; + count--; + + devc->irq_mode = IMODE_OUTPUT; + + save_flags (flags); + cli (); + if (sb_dsp_command (devc, 0x48)) /* DSP Block size */ + { + sb_dsp_command (devc, (unsigned char) (count & 0xff)); + sb_dsp_command (devc, (unsigned char) ((count >> 8) & 0xff)); + + if (devc->speed * devc->channels <= 23000) + cmd = 0x1c; /* 8 bit PCM output */ + else + cmd = 0x90; /* 8 bit high speed PCM output (SB2.01/Pro) */ + + if (!sb_dsp_command (devc, cmd)) + printk ("SB: Unable to start DAC\n"); + + } + else + printk ("SB: Unable to start DAC\n"); + restore_flags (flags); + devc->intr_active = 1; +} + +static void +sb20_audio_start_input (int dev, unsigned long buf, int nr_bytes, int intrflag, + int restart_dma) +{ + unsigned long flags; + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; + unsigned char cmd; + + /* + * Start a DMA input to the buffer pointed by dmaqtail + */ + + DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); + + if (audio_devs[dev]->dmachan1 > 3) + count >>= 1; + count--; + + devc->irq_mode = IMODE_INPUT; + + save_flags (flags); + cli (); + if (sb_dsp_command (devc, 0x48)) /* DSP Block size */ + { + sb_dsp_command (devc, (unsigned char) (count & 0xff)); + sb_dsp_command (devc, (unsigned char) ((count >> 8) & 0xff)); + + if (devc->speed * devc->channels <= (devc->major == 3 ? 23000 : 13000)) + cmd = 0x2c; /* 8 bit PCM input */ + else + cmd = 0x98; /* 8 bit high speed PCM input (SB2.01/Pro) */ + + if (!sb_dsp_command (devc, cmd)) + printk ("SB: Unable to start ADC\n"); + } + else + printk ("SB Error: Unable to start ADC\n"); + restore_flags (flags); + + devc->intr_active = 1; +} + +static void +sb20_audio_trigger (int dev, int bits) +{ + sb_devc *devc = audio_devs[dev]->devc; + + bits &= devc->irq_mode; + + if (!bits) + sb_dsp_command (devc, 0xd0); /* Halt DMA */ + else + { + switch (devc->irq_mode) + { + case IMODE_INPUT: + sb20_audio_start_input (dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag, devc->trg_restart); + break; + + case IMODE_OUTPUT: + sb20_audio_output_block (dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag, devc->trg_restart); + break; + } + } + + devc->trigger_bits = bits; +} + +/* + * SB2.01 specific speed setup + */ + +static int +sb201_audio_set_speed (int dev, int speed) +{ + sb_devc *devc = audio_devs[dev]->devc; + int tmp; + int s = speed * devc->channels; + + if (speed > 0) + { + if (speed < 4000) + speed = 4000; + + if (speed > 44100) + speed = 44100; + + if (devc->opened & OPEN_READ && speed > 15000) + speed = 15000; + + devc->tconst = ((65536 - ((256000000 + s / 2) / + s)) >> 8) & 0xff; + + tmp = 256 - devc->tconst; + speed = ((1000000 + tmp / 2) / tmp) / devc->channels; + + devc->speed = speed; + } + + return devc->speed; +} + +/* + * SB Pro specific routines + */ + +static int +sbpro_audio_prepare_for_input (int dev, int bsize, int bcount) +{ /* For SB Pro and Jazz16 */ + sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags; + unsigned char bits = 0; + + if (devc->dma16 >= 0 && devc->dma16 != devc->dma8) + audio_devs[dev]->dmachan1 = + audio_devs[dev]->dmachan2 = + devc->bits == 16 ? devc->dma16 : devc->dma8; + + if (devc->model == MDL_JAZZ || devc->model == MDL_SMW) + if (devc->bits == AFMT_S16_LE) + bits = 0x04; /* 16 bit mode */ + + save_flags (flags); + cli (); + if (sb_dsp_command (devc, 0x40)) + sb_dsp_command (devc, devc->tconst); + sb_dsp_command (devc, DSP_CMD_SPKOFF); + if (devc->channels == 1) + sb_dsp_command (devc, 0xa0 | bits); /* Mono input */ + else + sb_dsp_command (devc, 0xa8 | bits); /* Stereo input */ + restore_flags (flags); + + devc->trigger_bits = 0; + return 0; +} + +static int +sbpro_audio_prepare_for_output (int dev, int bsize, int bcount) +{ /* For SB Pro and Jazz16 */ + sb_devc *devc = audio_devs[dev]->devc; + unsigned long flags; + unsigned char tmp; + unsigned char bits = 0; + + if (devc->dma16 >= 0 && devc->dma16 != devc->dma8) + audio_devs[dev]->dmachan1 = + audio_devs[dev]->dmachan2 = + devc->bits == 16 ? devc->dma16 : devc->dma8; + + save_flags (flags); + cli (); + if (sb_dsp_command (devc, 0x40)) + sb_dsp_command (devc, devc->tconst); + sb_dsp_command (devc, DSP_CMD_SPKON); + + if (devc->model == MDL_JAZZ || devc->model == MDL_SMW) + { + if (devc->bits == AFMT_S16_LE) + bits = 0x04; /* 16 bit mode */ + + if (devc->channels == 1) + sb_dsp_command (devc, 0xa0 | bits); /* Mono output */ + else + sb_dsp_command (devc, 0xa8 | bits); /* Stereo output */ + } + else + { + tmp = sb_getmixer (devc, 0x0e); + if (devc->channels == 1) + tmp &= ~0x02; + else + tmp |= 0x02; + sb_setmixer (devc, 0x0e, tmp); + } + restore_flags (flags); + devc->trigger_bits = 0; + return 0; +} + +static int +sbpro_audio_set_speed (int dev, int speed) +{ + sb_devc *devc = audio_devs[dev]->devc; + + if (speed > 0) + { + if (speed < 4000) + speed = 4000; + + if (speed > 44100) + speed = 44100; + + if (devc->channels > 1 && speed > 22050) + speed = 22050; + + sb201_audio_set_speed (dev, speed); + } + + return devc->speed; +} + +static short +sbpro_audio_set_channels (int dev, short channels) +{ + sb_devc *devc = audio_devs[dev]->devc; + + if (channels == 1 || channels == 2) + if (channels != devc->channels) + { + devc->channels = channels; + sbpro_audio_set_speed (dev, devc->speed); + } + return devc->channels; +} + +static int +jazz16_audio_set_speed (int dev, int speed) +{ + sb_devc *devc = audio_devs[dev]->devc; + + if (speed > 0) + { + int tmp; + int s = speed * devc->channels; + + if (speed < 5000) + speed = 4000; + + if (speed > 44100) + speed = 44100; + + devc->tconst = ((65536 - ((256000000 + s / 2) / + s)) >> 8) & 0xff; + + tmp = 256 - devc->tconst; + speed = ((1000000 + tmp / 2) / tmp) / devc->channels; + + devc->speed = speed; + } + + return devc->speed; +} + +/* + * ESS specific routines + */ + +static void +ess_speed (sb_devc * devc) +{ + int divider; + unsigned char bits = 0; + int speed = devc->speed; + + if (speed < 4000) + speed = 4000; + else if (speed > 48000) + speed = 48000; + + if (speed > 22000) + { + bits = 0x80; + divider = 256 - (795500 + speed / 2) / speed; + } + else + { + divider = 128 - (397700 + speed / 2) / speed; + } + + bits |= (unsigned char) divider; + ess_write (devc, 0xa1, bits); + +/* + * Set filter divider register + */ + + speed = (speed * 9) / 20; /* Set filter roll-off to 90% of speed/2 */ + divider = 256 - 7160000 / (speed * 82); + ess_write (devc, 0xa2, divider); + + return; +} + +static int +ess_audio_prepare_for_input (int dev, int bsize, int bcount) +{ + sb_devc *devc = audio_devs[dev]->devc; + + ess_speed (devc); + sb_dsp_command (devc, DSP_CMD_SPKOFF); + + ess_write (devc, 0xb8, 0x0e); /* Auto init DMA mode */ + ess_write (devc, 0xa8, (ess_read (devc, 0xa8) & ~0x03) | + (3 - devc->channels)); /* Mono/stereo */ + ess_write (devc, 0xb9, 2); /* Demand mode (4 bytes/DMA request) */ + + if (devc->channels == 1) + { + if (devc->bits == AFMT_U8) + { /* 8 bit mono */ + ess_write (devc, 0xb7, 0x51); + ess_write (devc, 0xb7, 0xd0); + } + else + { /* 16 bit mono */ + ess_write (devc, 0xb7, 0x71); + ess_write (devc, 0xb7, 0xf4); + } + } + else + { /* Stereo */ + if (devc->bits == AFMT_U8) + { /* 8 bit stereo */ + ess_write (devc, 0xb7, 0x51); + ess_write (devc, 0xb7, 0x98); + } + else + { /* 16 bit stereo */ + ess_write (devc, 0xb7, 0x71); + ess_write (devc, 0xb7, 0xbc); + } + } + + ess_write (devc, 0xb1, (ess_read (devc, 0xb1) & 0x0f) | 0x50); + ess_write (devc, 0xb2, (ess_read (devc, 0xb2) & 0x0f) | 0x50); + + devc->trigger_bits = 0; + return 0; +} + +static int +ess_audio_prepare_for_output (int dev, int bsize, int bcount) +{ + sb_devc *devc = audio_devs[dev]->devc; + + sb_dsp_reset (devc); + ess_speed (devc); + + ess_write (devc, 0xb8, 4); /* Auto init DMA mode */ + ess_write (devc, 0xa8, (ess_read (devc, 0xa8) & ~0x03) | + (3 - devc->channels)); /* Mono/stereo */ + ess_write (devc, 0xb9, 2); /* Demand mode (4 bytes/request) */ + + if (devc->channels == 1) + { + if (devc->bits == AFMT_U8) + { /* 8 bit mono */ + ess_write (devc, 0xb6, 0x80); + ess_write (devc, 0xb7, 0x51); + ess_write (devc, 0xb7, 0xd0); + } + else + { /* 16 bit mono */ + ess_write (devc, 0xb6, 0x00); + ess_write (devc, 0xb7, 0x71); + ess_write (devc, 0xb7, 0xf4); + } + } + else + { /* Stereo */ + if (devc->bits == AFMT_U8) + { /* 8 bit stereo */ + ess_write (devc, 0xb6, 0x80); + ess_write (devc, 0xb7, 0x51); + ess_write (devc, 0xb7, 0x98); + } + else + { /* 16 bit stereo */ + ess_write (devc, 0xb6, 0x00); + ess_write (devc, 0xb7, 0x71); + ess_write (devc, 0xb7, 0xbc); + } + } + + ess_write (devc, 0xb1, (ess_read (devc, 0xb1) & 0x0f) | 0x50); + ess_write (devc, 0xb2, (ess_read (devc, 0xb2) & 0x0f) | 0x50); + sb_dsp_command (devc, DSP_CMD_SPKON); + + devc->trigger_bits = 0; + return 0; +} + +static void +ess_audio_output_block (int dev, unsigned long buf, int nr_bytes, + int intrflag, int restart_dma) +{ + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; + short c = -nr_bytes; + + if (!restart_dma) + return; + + DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); + + if (audio_devs[dev]->dmachan1 > 3) + count >>= 1; + count--; + + devc->irq_mode = IMODE_OUTPUT; + + ess_write (devc, 0xa4, (unsigned char) ((unsigned short) c & 0xff)); + ess_write (devc, 0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff)); + + ess_write (devc, 0xb8, ess_read (devc, 0xb8) | 0x05); /* Go */ + devc->intr_active = 1; +} + +static void +ess_audio_start_input (int dev, unsigned long buf, int nr_bytes, int intrflag, + int restart_dma) +{ + int count = nr_bytes; + sb_devc *devc = audio_devs[dev]->devc; + short c = -nr_bytes; + + if (!restart_dma) + return; + + /* + * Start a DMA input to the buffer pointed by dmaqtail + */ + + DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); + + if (audio_devs[dev]->dmachan1 > 3) + count >>= 1; + count--; + + devc->irq_mode = IMODE_INPUT; + + ess_write (devc, 0xa4, (unsigned char) ((unsigned short) c & 0xff)); + ess_write (devc, 0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff)); + + ess_write (devc, 0xb8, ess_read (devc, 0xb8) | 0x0f); /* Go */ + devc->intr_active = 1; +} + +static void +ess_audio_trigger (int dev, int bits) +{ + sb_devc *devc = audio_devs[dev]->devc; + + bits &= devc->irq_mode; + + if (!bits) + sb_dsp_command (devc, 0xd0); /* Halt DMA */ + else + { + switch (devc->irq_mode) + { + case IMODE_INPUT: + ess_audio_start_input (dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag, devc->trg_restart); + break; + + case IMODE_OUTPUT: + ess_audio_output_block (dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag, devc->trg_restart); + break; + } + } + + devc->trigger_bits = bits; +} + +/* + * SB16 specific routines + */ + +static int +sb16_audio_set_speed (int dev, int speed) +{ + sb_devc *devc = audio_devs[dev]->devc; + + if (speed > 0) + { + if (speed < 5000) + speed = 4000; + + if (speed > 44100) + speed = 44100; + + devc->speed = speed; + } + + return devc->speed; +} + +static unsigned int +sb16_audio_set_bits (int dev, unsigned int bits) +{ + sb_devc *devc = audio_devs[dev]->devc; + + if (bits != 0) + if (devc->bits == AFMT_U8 || bits == AFMT_S16_LE) + devc->bits = bits; + else + devc->bits = AFMT_U8; + + return devc->bits; +} + +static int +sb16_audio_prepare_for_input (int dev, int bsize, int bcount) +{ + sb_devc *devc = audio_devs[dev]->devc; + + audio_devs[dev]->dmachan1 = + audio_devs[dev]->dmachan2 = + devc->bits == AFMT_S16_LE ? devc->dma16 : devc->dma8; + + devc->trigger_bits = 0; + return 0; +} + +static int +sb16_audio_prepare_for_output (int dev, int bsize, int bcount) +{ + sb_devc *devc = audio_devs[dev]->devc; + + audio_devs[dev]->dmachan1 = + audio_devs[dev]->dmachan2 = + devc->bits == AFMT_S16_LE ? devc->dma16 : devc->dma8; + + devc->trigger_bits = 0; + return 0; +} + +static void +sb16_audio_output_block (int dev, unsigned long buf, int count, + int intrflag, int restart_dma) +{ + unsigned long flags, cnt; + sb_devc *devc = audio_devs[dev]->devc; + + devc->irq_mode = IMODE_OUTPUT; + devc->intr_active = 1; + + if (!restart_dma) + return; + + cnt = count; + if (devc->bits == AFMT_S16_LE) + cnt >>= 1; + cnt--; + + save_flags (flags); + cli (); + + if (restart_dma) + DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); + + sb_dsp_command (devc, 0x41); + sb_dsp_command (devc, (unsigned char) ((devc->speed >> 8) & 0xff)); + sb_dsp_command (devc, (unsigned char) (devc->speed & 0xff)); + + sb_dsp_command (devc, (devc->bits == AFMT_S16_LE ? 0xb6 : 0xc6)); + sb_dsp_command (devc, ((devc->channels == 2 ? 0x20 : 0) + + (devc->bits == AFMT_S16_LE ? 0x10 : 0))); + sb_dsp_command (devc, (unsigned char) (cnt & 0xff)); + sb_dsp_command (devc, (unsigned char) (cnt >> 8)); + + restore_flags (flags); +} + +static void +sb16_audio_start_input (int dev, unsigned long buf, int count, int intrflag, + int restart_dma) +{ + unsigned long flags, cnt; + sb_devc *devc = audio_devs[dev]->devc; + + devc->irq_mode = IMODE_INPUT; + devc->intr_active = 1; + + if (!restart_dma) + return; + + cnt = count; + if (devc->bits == AFMT_S16_LE) + cnt >>= 1; + cnt--; + + save_flags (flags); + cli (); + + if (restart_dma) + DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); + + sb_dsp_command (devc, 0x42); + sb_dsp_command (devc, (unsigned char) ((devc->speed >> 8) & 0xff)); + sb_dsp_command (devc, (unsigned char) (devc->speed & 0xff)); + + sb_dsp_command (devc, (devc->bits == AFMT_S16_LE ? 0xbe : 0xce)); + sb_dsp_command (devc, ((devc->channels == 2 ? 0x20 : 0) + + (devc->bits == AFMT_S16_LE ? 0x10 : 0))); + sb_dsp_command (devc, (unsigned char) (cnt & 0xff)); + sb_dsp_command (devc, (unsigned char) (cnt >> 8)); + + restore_flags (flags); +} + +static void +sb16_audio_trigger (int dev, int bits) +{ + sb_devc *devc = audio_devs[dev]->devc; + + bits &= devc->irq_mode; + + if (!bits) + sb_dsp_command (devc, 0xd0); /* Halt DMA */ + else + { + switch (devc->irq_mode) + { + case IMODE_INPUT: + sb16_audio_start_input (dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag, devc->trg_restart); + break; + + case IMODE_OUTPUT: + sb16_audio_output_block (dev, devc->trg_buf, devc->trg_bytes, + devc->trg_intrflag, devc->trg_restart); + break; + } + } + + devc->trigger_bits = bits; +} + +static int +sb_audio_ioctl (int dev, unsigned int cmd, caddr_t arg, int local) +{ + return -(EINVAL); +} + +static void +sb_audio_reset (int dev) +{ + unsigned long flags; + sb_devc *devc = audio_devs[dev]->devc; + + save_flags (flags); + cli (); + sb_dsp_reset (devc); + restore_flags (flags); +} + +static struct audio_driver sb1_audio_driver = /* SB1.x */ +{ + sb_audio_open, + sb_audio_close, + sb_set_output_parms, + sb_set_input_parms, + sb_audio_ioctl, + sb1_audio_prepare_for_input, + sb1_audio_prepare_for_output, + sb_audio_reset, + sb1_audio_halt_xfer, + NULL, /* local_qlen */ + NULL, /* copy_from_user */ + NULL, + NULL, + sb1_audio_trigger, + sb1_audio_set_speed, + sb1_audio_set_bits, + sb1_audio_set_channels +}; + +static struct audio_driver sb20_audio_driver = /* SB2.0 */ +{ + sb_audio_open, + sb_audio_close, + sb_set_output_parms, + sb_set_input_parms, + sb_audio_ioctl, + sb1_audio_prepare_for_input, + sb1_audio_prepare_for_output, + sb_audio_reset, + sb1_audio_halt_xfer, + NULL, /* local_qlen */ + NULL, /* copy_from_user */ + NULL, + NULL, + sb20_audio_trigger, + sb1_audio_set_speed, + sb1_audio_set_bits, + sb1_audio_set_channels +}; + +static struct audio_driver sb201_audio_driver = /* SB2.01 */ +{ + sb_audio_open, + sb_audio_close, + sb_set_output_parms, + sb_set_input_parms, + sb_audio_ioctl, + sb1_audio_prepare_for_input, + sb1_audio_prepare_for_output, + sb_audio_reset, + sb1_audio_halt_xfer, + NULL, /* local_qlen */ + NULL, /* copy_from_user */ + NULL, + NULL, + sb20_audio_trigger, + sb201_audio_set_speed, + sb1_audio_set_bits, + sb1_audio_set_channels +}; + +static struct audio_driver sbpro_audio_driver = /* SB Pro */ +{ + sb_audio_open, + sb_audio_close, + sb_set_output_parms, + sb_set_input_parms, + sb_audio_ioctl, + sbpro_audio_prepare_for_input, + sbpro_audio_prepare_for_output, + sb_audio_reset, + sb1_audio_halt_xfer, + NULL, /* local_qlen */ + NULL, /* copy_from_user */ + NULL, + NULL, + sb20_audio_trigger, + sbpro_audio_set_speed, + sb1_audio_set_bits, + sbpro_audio_set_channels +}; + +static struct audio_driver jazz16_audio_driver = /* Jazz16 and SM Wave */ +{ + sb_audio_open, + sb_audio_close, + sb_set_output_parms, + sb_set_input_parms, + sb_audio_ioctl, + sbpro_audio_prepare_for_input, + sbpro_audio_prepare_for_output, + sb_audio_reset, + sb1_audio_halt_xfer, + NULL, /* local_qlen */ + NULL, /* copy_from_user */ + NULL, + NULL, + sb20_audio_trigger, + jazz16_audio_set_speed, + sb16_audio_set_bits, + sbpro_audio_set_channels +}; + +static struct audio_driver sb16_audio_driver = /* SB16 */ +{ + sb_audio_open, + sb_audio_close, + sb_set_output_parms, + sb_set_input_parms, + sb_audio_ioctl, + sb16_audio_prepare_for_input, + sb16_audio_prepare_for_output, + sb_audio_reset, + sb1_audio_halt_xfer, + NULL, /* local_qlen */ + NULL, /* copy_from_user */ + NULL, + NULL, + sb16_audio_trigger, + sb16_audio_set_speed, + sb16_audio_set_bits, + sbpro_audio_set_channels +}; + +static struct audio_driver ess_audio_driver = /* ESS ES688/1688 */ +{ + sb_audio_open, + sb_audio_close, + sb_set_output_parms, + sb_set_input_parms, + sb_audio_ioctl, + ess_audio_prepare_for_input, + ess_audio_prepare_for_output, + sb_audio_reset, + sb1_audio_halt_xfer, + NULL, /* local_qlen */ + NULL, /* copy_from_user */ + NULL, + NULL, + ess_audio_trigger, + sb16_audio_set_speed, + sb16_audio_set_bits, + sbpro_audio_set_channels +}; + +void +sb_audio_init (sb_devc * devc, char *name) +{ + int audio_flags = 0; + int format_mask = AFMT_U8; + + struct audio_driver *driver = &sb1_audio_driver; + + switch (devc->model) + { + case MDL_SB1: /* SB1.0 or SB 1.5 */ + DDB (printk ("Will use standard SB1.x driver\n")); + audio_flags = DMA_HARDSTOP; + break; + + case MDL_SB2: + DDB (printk ("Will use SB2.0 driver\n")); + audio_flags = DMA_AUTOMODE; + driver = &sb20_audio_driver; + break; + + case MDL_SB201: + DDB (printk ("Will use SB2.01 (high speed) driver\n")); + audio_flags = DMA_AUTOMODE; + driver = &sb201_audio_driver; + break; + + case MDL_JAZZ: + case MDL_SMW: + DDB (printk ("Will use Jazz16 driver\n")); + audio_flags = DMA_AUTOMODE; + format_mask |= AFMT_S16_LE; + driver = &jazz16_audio_driver; + break; + + case MDL_ESS: + DDB (printk ("Will use ESS ES688/1688 driver\n")); + audio_flags = DMA_AUTOMODE; + format_mask |= AFMT_S16_LE; + driver = &ess_audio_driver; + break; + + case MDL_SB16: + DDB (printk ("Will use SB16 driver\n")); + audio_flags = DMA_AUTOMODE; + format_mask |= AFMT_S16_LE; + driver = &sb16_audio_driver; + break; + + default: + DDB (printk ("Will use SB Pro driver\n")); + audio_flags = DMA_AUTOMODE; + driver = &sbpro_audio_driver; + } + + if ((devc->my_dev = sound_install_audiodrv (AUDIO_DRIVER_VERSION, + name, + driver, + sizeof (struct audio_driver), + audio_flags, + format_mask, + devc, + devc->dma8, + devc->dma8)) < 0) + { + return; + } + + audio_devs[devc->my_dev]->mixer_dev = devc->my_mixerdev; + audio_devs[devc->my_dev]->min_fragment = 5; +} + +#endif diff -ur --new-file old/linux/drivers/sound/sb_card.c new/linux/drivers/sound/sb_card.c --- old/linux/drivers/sound/sb_card.c Sun Mar 24 21:50:18 1996 +++ new/linux/drivers/sound/sb_card.c Thu Aug 1 14:43:05 1996 @@ -1,51 +1,31 @@ /* * sound/sb_card.c * - * Detection routine for the SoundBlaster cards. + * Detection routine for the Sound Blaster cards. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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 "sound_config.h" -#if defined(CONFIG_SB) +#if defined(CONFIG_SBDSP) +#include "sb_mixer.h" #include "sb.h" -long -attach_sb_card (long mem_start, struct address_info *hw_config) +void +attach_sb_card (struct address_info *hw_config) { #if defined(CONFIG_AUDIO) || defined(CONFIG_MIDI) - if (!sb_dsp_detect (hw_config)) - return mem_start; - mem_start = sb_dsp_init (mem_start, hw_config); - request_region (hw_config->io_base, 16, "SoundBlaster"); + sb_dsp_init (hw_config); #endif - - return mem_start; } int @@ -64,7 +44,6 @@ void unload_sb (struct address_info *hw_config) { - release_region (hw_config->io_base, 16); sb_dsp_unload (hw_config); } diff -ur --new-file old/linux/drivers/sound/sb_common.c new/linux/drivers/sound/sb_common.c --- old/linux/drivers/sound/sb_common.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/sound/sb_common.c Sun Aug 4 11:42:54 1996 @@ -0,0 +1,1240 @@ +/* + * sound/sb_common.c + * + * Common routines for Sound Blaster compatible cards. + */ +/* + * Copyright (C) by Hannu Savolainen 1993-1996 + * + * USS/Lite 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 "sound_config.h" + +#if defined(CONFIG_SBDSP) + +#ifndef CONFIG_AUDIO +#error You will need to configure the sound driver with CONFIG_AUDIO option. +#endif + +#include "sb_mixer.h" +#include "sb.h" + +static sb_devc *detected_devc = NULL; /* For communication from probe to init */ +static sb_devc *last_devc = NULL; /* For MPU401 initialization */ +static sb_devc *irq2devc[16] = +{NULL}; +static unsigned char jazz_irq_bits[] = +{0, 0, 2, 3, 0, 1, 0, 4, 0, 2, 5, 0, 0, 0, 0, 6}; +static unsigned char jazz_dma_bits[] = +{0, 1, 0, 2, 0, 3, 0, 4}; + +/* + * Jazz16 chipset specific control variables + */ + +static int jazz16_base = 0; /* Not detected */ +static unsigned char jazz16_bits = 0; /* I/O relocation bits */ + +/* + * Logitech SoundMan Wave specific initialization code + */ + +#ifdef SMW_MIDI0001_INCLUDED +#include "smw-midi0001.h" +#else +unsigned char *smw_ucode = NULL; +int smw_ucodeLen = 0; + +#endif + +int +sb_dsp_command (sb_devc * devc, unsigned char val) +{ + int i; + unsigned long limit; + + limit = jiffies + HZ / 10; /* + * The timeout is 0.1 seconds + */ + + /* + * Note! the i<500000 is an emergency exit. The sb_dsp_command() is sometimes + * called while interrupts are disabled. This means that the timer is + * disabled also. However the timeout situation is a abnormal condition. + * Normally the DSP should be ready to accept commands after just couple of + * loops. + */ + + for (i = 0; i < 500000 && jiffies < limit; i++) + { + if ((inb (DSP_STATUS) & 0x80) == 0) + { + outb (val, DSP_COMMAND); + return 1; + } + } + + printk ("Sound Blaster: DSP Command(%x) Timeout.\n", val); + return 0; +} + +int +sb_dsp_get_byte (sb_devc * devc) +{ + int i; + + for (i = 1000; i; i--) + if (inb (DSP_DATA_AVAIL) & 0x80) + { + return inb (DSP_READ); + } + + return 0xffff; +} + +int +ess_write (sb_devc * devc, unsigned char reg, unsigned char data) +{ + /* Write a byte to an extended mode register of ES1688 */ + + if (!sb_dsp_command (devc, reg)) + return 0; + + return sb_dsp_command (devc, data); +} + +int +ess_read (sb_devc * devc, unsigned char reg) +{ +/* Read a byte from an extended mode register of ES1688 */ + + if (!sb_dsp_command (devc, 0xc0)) /* Read register command */ + return -1; + + if (!sb_dsp_command (devc, reg)) + return -1; + + return sb_dsp_get_byte (devc); +} + +void +sbintr (int irq, void *dev_id, struct pt_regs *dummy) +{ + int status; + unsigned char src = 0xff; + + sb_devc *devc = irq2devc[irq]; + + if (devc == NULL || devc->irq != irq) + { + DEB (printk ("sbintr: Bogus interrupt IRQ%d\n", irq)); + return; + } + + devc->irq_ok = 1; + + if (devc->model == MDL_SB16) + { + + src = sb_getmixer (devc, IRQ_STAT); /* Interrupt source register */ + +#if defined(CONFIG_MIDI) && defined(CONFIG_UART401) + if (src & 4) + uart401intr (devc->irq, NULL, NULL); /* MPU401 interrupt */ +#endif + + if (!(src & 3)) + return; /* Not a DSP interrupt */ + } + + if (devc->intr_active) + switch (devc->irq_mode) + { + case IMODE_OUTPUT: + DMAbuf_outputintr (devc->dev, 1); + break; + + case IMODE_INPUT: + DMAbuf_inputintr (devc->dev); + break; + + case IMODE_INIT: + break; + + case IMODE_MIDI: +#ifdef CONFIG_MIDI + sb_midi_interrupt (devc); +#endif + break; + + default: + printk ("Sound Blaster: Unexpected interrupt\n"); + } +/* + * Acknowledge interrupts + */ + + if (src & 0x01) + status = inb (DSP_DATA_AVAIL); + + if (devc->model == MDL_SB16 && src & 0x02) + status = inb (DSP_DATA_AVL16); +} + +int +sb_dsp_reset (sb_devc * devc) +{ + int loopc; + + if (devc->model == MDL_ESS) + outb (3, DSP_RESET); /* Reset FIFO too */ + else + outb (1, DSP_RESET); + + tenmicrosec (devc->osp); + outb (0, DSP_RESET); + tenmicrosec (devc->osp); + tenmicrosec (devc->osp); + tenmicrosec (devc->osp); + + for (loopc = 0; loopc < 1000 && !(inb (DSP_DATA_AVAIL) & 0x80); loopc++); + + if (inb (DSP_READ) != 0xAA) + return 0; /* Sorry */ + + if (devc->model == MDL_ESS) + sb_dsp_command (devc, 0xc6); /* Enable extended mode */ + + return 1; +} + +static void +dsp_get_vers (sb_devc * devc) +{ + int i; + + unsigned long flags; + + save_flags (flags); + cli (); + devc->major = devc->minor = 0; + sb_dsp_command (devc, 0xe1); /* Get version */ + + for (i = 100000; i; i--) + { + if (inb (DSP_DATA_AVAIL) & 0x80) + { + if (devc->major == 0) + devc->major = inb (DSP_READ); + else + { + devc->minor = inb (DSP_READ); + break; + } + } + } + restore_flags (flags); +} + +static int +sb16_set_dma_hw (sb_devc * devc) +{ + int bits; + + if (devc->dma8 != 0 && devc->dma8 != 1 && devc->dma8 != 3) + { + printk ("SB16: Invalid 8 bit DMA (%d)\n", devc->dma8); + return 0; + } + + bits = (1 << devc->dma8); + + if (devc->dma16 >= 5 && devc->dma16 <= 7) + bits |= (1 << devc->dma16); + + sb_setmixer (devc, DMA_NR, bits); + return 1; +} + +static void +sb16_set_mpu_port(sb_devc *devc, struct address_info *hw_config) +{ +/* + * This routine initializes new MIDI port setup register of SB Vibra. + */ + unsigned char bits = sb_getmixer(devc, 0x84) & ~0x06; + switch (hw_config->io_base) + { + case 0x300: + sb_setmixer (devc, 0x84, bits | 0x04); + break; + + case 0x330: + sb_setmixer (devc, 0x84, bits | 0x00); + break; + + default: + sb_setmixer (devc, 0x84, bits | 0x02); /* Disable MPU */ + printk("SB16: Invalid MIDI I/O port %x\n", hw_config->io_base); + } +} + +static int +sb16_set_irq_hw (sb_devc * devc, int level) +{ + int ival; + + switch (level) + { + case 5: + ival = 2; + break; + case 7: + ival = 4; + break; + case 9: + ival = 1; + break; + case 10: + ival = 8; + break; + default: + printk ("SB16 IRQ%d is not possible\n", level); + return 0; + } + sb_setmixer (devc, IRQ_NR, ival); + return 1; +} + +static void +relocate_Jazz16 (sb_devc * devc, struct address_info *hw_config) +{ + unsigned char bits = 0; + unsigned long flags; + + if (jazz16_base != 0 && jazz16_base != hw_config->io_base) + return; + + switch (hw_config->io_base) + { + case 0x220: + bits = 1; + break; + case 0x240: + bits = 2; + break; + case 0x260: + bits = 3; + break; + + default: + return; + } + + bits = jazz16_bits = bits << 5; + + jazz16_base = hw_config->io_base; + +/* + * Magic wake up sequence by writing to 0x201 (aka Joystick port) + */ + save_flags (flags); + cli (); + outb (0xAF, 0x201); + outb (0x50, 0x201); + outb (bits, 0x201); + restore_flags (flags); +} + +static int +init_Jazz16 (sb_devc * devc, struct address_info *hw_config) +{ + char name[100]; + +/* + * First try to check that the card has Jazz16 chip. It identifies itself + * by returning 0x12 as response to DSP command 0xfa. + */ + + if (!sb_dsp_command (devc, 0xfa)) + return 0; + + if (sb_dsp_get_byte (devc) != 0x12) + return 0; + +/* + * OK so far. Now configure the IRQ and DMA channel used by the card. + */ + if (hw_config->irq < 1 || hw_config->irq > 15 || + jazz_irq_bits[hw_config->irq] == 0) + { + printk ("Jazz16: Invalid interrupt (IRQ%d)\n", hw_config->irq); + return 0; + } + + if (hw_config->dma < 0 || hw_config->dma > 3 || + jazz_dma_bits[hw_config->dma] == 0) + { + printk ("Jazz16: Invalid 8 bit DMA (DMA%d)\n", hw_config->dma); + return 0; + } + + if (hw_config->dma2 < 0) + { + printk ("Jazz16: No 16 bit DMA channel defined\n"); + return 0; + } + + if (hw_config->dma2 < 5 || hw_config->dma2 > 7 || + jazz_dma_bits[hw_config->dma2] == 0) + { + printk ("Jazz16: Invalid 16 bit DMA (DMA%d)\n", hw_config->dma2); + return 0; + } + + devc->dma16 = hw_config->dma2; + + if (!sb_dsp_command (devc, 0xfb)) + return 0; + + if (!sb_dsp_command (devc, jazz_dma_bits[hw_config->dma] | + (jazz_dma_bits[hw_config->dma2] << 4))) + return 0; + + if (!sb_dsp_command (devc, jazz_irq_bits[hw_config->irq])) + return 0; + +/* + * Now we have configured a standard Jazz16 device. + */ + devc->model = MDL_JAZZ; + strcpy (name, "Jazz16"); + + + hw_config->name = (char *) (sound_mem_blocks[sound_nblocks] = vmalloc (strlen (name + 1))); + if (sound_nblocks < 1024) + sound_nblocks++;; + if (hw_config->name != NULL) + strcpy (hw_config->name, name); + devc->caps |= SB_NO_MIDI; + return 1; +} + +static int +ess_init (sb_devc * devc, struct address_info *hw_config) +{ + unsigned char cfg, irq_bits = 0, dma_bits = 0; + int ess_major = 0, ess_minor = 0; + int i; + char name[100]; + +/* + * Try to detect ESS chips. + */ + + sb_dsp_command (devc, 0xe7); /* Return identification */ + + for (i = 1000; i; i--) + { + if (inb (DSP_DATA_AVAIL) & 0x80) + { + if (ess_major == 0) + ess_major = inb (DSP_READ); + else + { + ess_minor = inb (DSP_READ); + break; + } + } + } + + if (ess_major == 0) + return 0; + + if (ess_major == 0x48 && (ess_minor & 0xf0) == 0x80) + { + sprintf (name, "ESS ES488 AudioDrive (rev %d)", + ess_minor & 0x0f); + hw_config->name = name; + devc->model = MDL_SBPRO; + return 1; + } + else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80) + { + sprintf (name, + "ESS ES1688 AudioDrive (rev %d)", + ess_minor & 0x0f); + } + else + strcpy (name, "Jazz16"); + + devc->model = MDL_ESS; + devc->submodel = ess_minor & 0x0f; + + hw_config->name = (char *) (sound_mem_blocks[sound_nblocks] = vmalloc (strlen (name + 1))); + if (sound_nblocks < 1024) + sound_nblocks++;; + if (hw_config->name != NULL) + strcpy (hw_config->name, name); + + + sb_dsp_reset (devc); /* Turn on extended mode */ + +/* + * Set IRQ configuration register + */ + + cfg = 0x50; /* Enable only DMA counter interrupt */ + + switch (devc->irq) + { + case 2: + case 9: + irq_bits = 0; + break; + + case 5: + irq_bits = 1; + break; + + case 7: + irq_bits = 2; + break; + + case 10: + irq_bits = 3; + break; + + default: + irq_bits = 0; + cfg = 0x10; /* Disable all interrupts */ + printk ("\nESS1688: Invalid IRQ %d\n", devc->irq); + return 0; + } + + if (!ess_write (devc, 0xb1, cfg | (irq_bits << 2))) + printk ("\nESS1688: Failed to write to IRQ config register\n"); + +/* + * Set DMA configuration register + */ + + cfg = 0x50; /* Extended mode DMA enable */ + + if (devc->dma8 > 3 || devc->dma8 < 0 || devc->dma8 == 2) + { + dma_bits = 0; + cfg = 0x00; /* Disable all DMA */ + printk ("\nESS1688: Invalid DMA %d\n", devc->dma8); + } + else + { + if (devc->dma8 == 3) + dma_bits = 3; + else + dma_bits = devc->dma8 + 1; + } + + if (!ess_write (devc, 0xb2, cfg | (dma_bits << 2))) + printk ("\nESS1688: Failed to write to DMA config register\n"); + +/* + * Enable joystick and OPL3 + */ + + cfg = sb_getmixer (devc, 0x40); + sb_setmixer (devc, 0x40, cfg | 0x03); + if (devc->submodel >= 8) /* ES1688 */ + devc->caps |= SB_NO_MIDI; /* ES1688 uses MPU401 MIDI mode */ + sb_dsp_reset (devc); + return 1; +} + +int +sb_dsp_detect (struct address_info *hw_config) +{ + sb_devc sb_info; + sb_devc *devc = &sb_info; + +/* + * Initialize variables + */ + DDB (printk ("sb_dsp_detect(%x) entered\n", hw_config->io_base)); + if (check_region (hw_config->io_base, 16)) + return 0; + + memset ((char *) &sb_info, 0, sizeof (sb_info)); /* Zero everything */ + + devc->osp = hw_config->osp; + devc->type = hw_config->card_subtype; + + devc->base = hw_config->io_base; + devc->irq = hw_config->irq; + devc->dma8 = hw_config->dma; + + devc->dma16 = -1; + +/* + * Detect the device + */ + + if (sb_dsp_reset (devc)) + dsp_get_vers (devc); + else + devc->major = 0; + + if (devc->type == 0 || devc->type == MDL_JAZZ || devc->type == MDL_SMW) + if (devc->major == 0 || (devc->major == 3 && devc->minor == 1)) + relocate_Jazz16 (devc, hw_config); + + if (!sb_dsp_reset (devc)) + { + DDB (printk ("SB reset failed\n")); + return 0; + } + + if (devc->major == 0) + dsp_get_vers (devc); + + if (devc->major == 3 && devc->minor == 1) + if (devc->type == MDL_AZTECH) /* SG Washington? */ + { + if (sb_dsp_command (devc, 0x09)) + if (sb_dsp_command (devc, 0x00)) /* Enter WSS mode */ + { + int i; + + /* Have some delay */ + for (i = 0; i < 10000; i++) + inb (DSP_DATA_AVAIL); + devc->caps = SB_NO_AUDIO | SB_NO_MIDI; /* Mixer only */ + } + } + +/* + * Save device information for sb_dsp_init() + */ + + + detected_devc = (sb_devc *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (sb_devc))); + if (sound_nblocks < 1024) + sound_nblocks++;; + + if (detected_devc == NULL) + { + printk ("sb: Can't allocate memory for device information\n"); + return 0; + } + + memcpy ((char *) detected_devc, (char *) devc, sizeof (sb_devc)); + + DDB (printk ("SB %d.%d detected OK (%x)\n", devc->major, devc->minor, + hw_config->io_base)); + return 1; +} + +void +sb_dsp_init (struct address_info *hw_config) +{ + sb_devc *devc; + char name[100]; + +#ifndef NO_SB_IRQ_TEST + int n; +#endif + +/* + * Check if we had detected a SB device earlier + */ + DDB (printk ("sb_dsp_init(%x) entered\n", hw_config->io_base)); + + if (detected_devc == NULL) + { + DDB (printk ("No detected device\n")); + return; + } + + devc = detected_devc; + detected_devc = NULL; + + if (devc->base != hw_config->io_base) + { + DDB (printk ("I/O port mismatch\n")); + return; + } + +/* + * Now continue initialization of the device + */ + devc->dev = num_audiodevs; + devc->caps = hw_config->driver_use_1; + + irq2devc[hw_config->irq] = devc; + devc->irq_ok = 0; + + if (snd_set_irq_handler (hw_config->irq, + sbintr, "sound blaster", devc->osp) < 0) + { + printk ("SB: Can't allocate IRQ%d\n", hw_config->irq); + irq2devc[hw_config->irq] = NULL; + return; + } + + if (devc->major == 4) + if (!sb16_set_irq_hw (devc, devc->irq)) /* Unsupported IRQ */ + { + snd_release_irq (devc->irq); + return; + } + + if ((devc->type == 0 || devc->type == MDL_ESS) && + devc->major == 3 && devc->minor == 1) + { /* Handle various chipsets which claim they are SB Pro compatible */ + if ((devc->type != 0 && devc->type != MDL_ESS) || + !ess_init (devc, hw_config)) + if ((devc->type != 0 && devc->type != MDL_JAZZ && + devc->type != MDL_SMW) || !init_Jazz16 (devc, hw_config)) + { + DDB (printk ("This is a genuine SB Pro\n")); + } + } + +#ifndef NO_SB_IRQ_TEST + for (n = 0; n < 3 && devc->irq_ok == 0; n++) + if (sb_dsp_command (devc, 0xf2)) /* Cause interrupt immediately */ + { + int i; + + for (i = 0; !devc->irq_ok && i < 10000; i++); + } + + if (!devc->irq_ok) + { + printk ("sb: Interrupt test on IRQ%d failed - device disabled\n", devc->irq); + snd_release_irq (devc->irq); + return; + } + else + { + DDB (printk ("IRQ test OK (IRQ%d)\n", devc->irq)); + } +#endif + + request_region (hw_config->io_base, 16, "sound blaster"); + + switch (devc->major) + { + case 1: /* SB 1.0 or 1.5 */ + devc->model = hw_config->card_subtype = MDL_SB1; + break; + + case 2: /* SB 2.x */ + if (devc->minor == 0) + devc->model = hw_config->card_subtype = MDL_SB2; + else + devc->model = hw_config->card_subtype = MDL_SB201; + break; + + case 3: /* SB Pro and most clones */ + if (devc->model == 0) + { + devc->model = hw_config->card_subtype = MDL_SBPRO; + if (hw_config->name == NULL) + hw_config->name = "Sound Blaster Pro"; + } + break; + + case 4: + devc->model = hw_config->card_subtype = MDL_SB16; + if (hw_config->name == NULL) + hw_config->name = "Sound Blaster 16"; + + if (hw_config->dma2 == -1) + devc->dma16 = devc->dma8; + else if (hw_config->dma2 < 5 || hw_config->dma2 > 7) + { + printk ("SB16: Bad or missing 16 bit DMA channel\n"); + devc->dma16 = devc->dma8; + } + else + devc->dma16 = hw_config->dma2; + + sb16_set_dma_hw (devc); + devc->caps |= SB_NO_MIDI; + } + + if (!(devc->caps & SB_NO_MIXER)) + if (devc->major == 3 || devc->major == 4) + sb_mixer_init (devc); + +#ifdef CONFIG_MIDI + if (!(devc->caps & SB_NO_MIDI)) + sb_dsp_midi_init (devc); +#endif + + if (hw_config->name == NULL) + hw_config->name = "Sound Blaster"; + + sprintf (name, "%s (%d.%d)", hw_config->name, devc->major, devc->minor); + conf_printf (name, hw_config); + hw_config->card_subtype = devc->model; + last_devc = devc; /* For SB MPU detection */ + + if (!(devc->caps & SB_NO_AUDIO)) + { + if (sound_alloc_dma (devc->dma8, "Sound Blaster8")) + { + printk ("SB: Can't allocate 8 bit DMA channel %d\n", devc->dma8); + } + if (devc->dma16 >= 0 && devc->dma16 != devc->dma8) + if (sound_alloc_dma (devc->dma16, "Sound Blaster16")) + { + printk ("SB: Can't allocate 16 bit DMA channel %d\n", devc->dma16); + } + sb_audio_init (devc, name); + } +} + +void +sb_dsp_disable_midi (int io_base) +{ +} + +void +sb_dsp_disable_recording (int io_base) +{ +} + +void +sb_dsp_unload (struct address_info *hw_config) +{ + sb_devc *devc; + int irq = hw_config->irq; + + if (irq < 0) + irq *= -1; + + devc = irq2devc[irq]; + + if (devc && devc->base == hw_config->io_base) + { + release_region (devc->base, 16); + if (!(devc->caps & SB_NO_AUDIO)) + { + sound_free_dma (devc->dma8); + + if (devc->dma16 >= 0) + sound_free_dma (devc->dma16); + } + + snd_release_irq (devc->irq); + irq2devc[devc->irq] = NULL; + } +} + +/* + * Mixer access routines + */ + +void +sb_setmixer (sb_devc * devc, unsigned int port, unsigned int value) +{ + unsigned long flags; + + save_flags (flags); + cli (); + outb ((unsigned char) (port & 0xff), MIXER_ADDR); + + tenmicrosec (devc->osp); + outb ((unsigned char) (value & 0xff), MIXER_DATA); + tenmicrosec (devc->osp); + restore_flags (flags); +} + +unsigned int +sb_getmixer (sb_devc * devc, unsigned int port) +{ + unsigned int val; + unsigned long flags; + + save_flags (flags); + cli (); + outb ((unsigned char) (port & 0xff), MIXER_ADDR); + + tenmicrosec (devc->osp); + val = inb (MIXER_DATA); + tenmicrosec (devc->osp); + restore_flags (flags); + + return val; +} + +#ifdef CONFIG_MIDI +/* + * MPU401 MIDI initialization. + */ + +static void +smw_putmem (sb_devc * devc, int base, int addr, unsigned char val) +{ + unsigned long flags; + + save_flags (flags); + cli (); + + outb (addr & 0xff, base + 1); /* Low address bits */ + outb (addr >> 8, base + 2); /* High address bits */ + outb (val, base); /* Data */ + + restore_flags (flags); +} + +static unsigned char +smw_getmem (sb_devc * devc, int base, int addr) +{ + unsigned long flags; + unsigned char val; + + save_flags (flags); + cli (); + + outb (addr & 0xff, base + 1); /* Low address bits */ + outb (addr >> 8, base + 2); /* High address bits */ + val = inb (base); /* Data */ + + restore_flags (flags); + return val; +} + +static int +smw_midi_init (sb_devc * devc, struct address_info *hw_config) +{ + int mpu_base = hw_config->io_base; + int mp_base = mpu_base + 4; /* Microcontroller base */ + int i; + unsigned char control; + + + /* + * Reset the microcontroller so that the RAM can be accessed + */ + + control = inb (mpu_base + 7); + outb (control | 3, mpu_base + 7); /* Set last two bits to 1 (?) */ + outb ((control & 0xfe) | 2, mpu_base + 7); /* xxxxxxx0 resets the mc */ + + for (i = 0; i < 300; i++) /* Wait at least 1ms */ + tenmicrosec (devc->osp); + + outb (control & 0xfc, mpu_base + 7); /* xxxxxx00 enables RAM */ + + /* + * Detect microcontroller by probing the 8k RAM area + */ + smw_putmem (devc, mp_base, 0, 0x00); + smw_putmem (devc, mp_base, 1, 0xff); + tenmicrosec (devc->osp); + + if (smw_getmem (devc, mp_base, 0) != 0x00 || smw_getmem (devc, mp_base, 1) != 0xff) + { + DDB (printk ("\nSM Wave: No microcontroller RAM detected (%02x, %02x)\n", + smw_getmem (devc, mp_base, 0), smw_getmem (devc, mp_base, 1))); + return 0; /* No RAM */ + } + + /* + * There is RAM so assume it's really a SM Wave + */ + + devc->model = MDL_SMW; + smw_mixer_init (devc); + + if (smw_ucodeLen > 0) + { + if (smw_ucodeLen != 8192) + { + printk ("\nSM Wave: Invalid microcode (MIDI0001.BIN) length\n"); + return 1; + } + + /* + * Download microcode + */ + + for (i = 0; i < 8192; i++) + smw_putmem (devc, mp_base, i, smw_ucode[i]); + + /* + * Verify microcode + */ + + for (i = 0; i < 8192; i++) + if (smw_getmem (devc, mp_base, i) != smw_ucode[i]) + { + printk ("SM Wave: Microcode verification failed\n"); + return 0; + } + } + + control = 0; +#ifdef SMW_SCSI_IRQ + /* + * Set the SCSI interrupt (IRQ2/9, IRQ3 or IRQ10). The SCSI interrupt + * is disabled by default. + * + * BTW the Zilog 5380 SCSI controller is located at MPU base + 0x10. + */ + { + static unsigned char scsi_irq_bits[] = + {0, 0, 3, 1, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0}; + + control |= scsi_irq_bits[SMW_SCSI_IRQ] << 6; + } +#endif + +#ifdef SMW_OPL4_ENABLE + /* + * Make the OPL4 chip visible on the PC bus at 0x380. + * + * There is no need to enable this feature since this driver + * doesn't support OPL4 yet. Also there is no RAM in SM Wave so + * enabling OPL4 is pretty useless. + */ + control |= 0x10; /* Uses IRQ12 if bit 0x20 == 0 */ + /* control |= 0x20; Uncomment this if you want to use IRQ7 */ +#endif + + outb (control | 0x03, mpu_base + 7); /* xxxxxx11 restarts */ + hw_config->name = "SoundMan Wave"; + return 1; +} + +static int +ess_midi_init (sb_devc * devc, struct address_info *hw_config) +{ + unsigned char cfg, tmp; + + cfg = sb_getmixer (devc, 0x40) & 0x03; + + if (devc->submodel < 8) + { + sb_setmixer (devc, 0x40, cfg | 0x03); /* Enable OPL3 & joystick */ + return 0; /* ES688 doesn't support MPU401 mode */ + } + + tmp = (hw_config->io_base & 0x0f0) >> 4; + + if (tmp > 3) + { + sb_setmixer (devc, 0x40, cfg); + return 0; + } + + cfg |= tmp << 3; + + tmp = 1; /* MPU enabled without interrupts */ + + switch (hw_config->irq) + { + case 9: + tmp = 0x4; + break; + case 5: + tmp = 0x5; + break; + case 7: + tmp = 0x6; + break; + case 10: + tmp = 0x7; + break; + default: + return 0; + } + + cfg |= tmp << 5; + + sb_setmixer (devc, 0x40, cfg | 0x03); + return 1; +} + +static int +init_Jazz16_midi (sb_devc * devc, struct address_info *hw_config) +{ + int mpu_base = hw_config->io_base; + int sb_base = devc->base; + int irq = hw_config->irq; + + unsigned char bits = 0; + unsigned long flags; + + if (irq < 0) + irq *= -1; + + if (irq < 1 || irq > 15 || + jazz_irq_bits[irq] == 0) + { + printk ("Jazz16: Invalid MIDI interrupt (IRQ%d)\n", irq); + return 0; + } + + switch (sb_base) + { + case 0x220: + bits = 1; + break; + case 0x240: + bits = 2; + break; + case 0x260: + bits = 3; + break; + + default: + return 0; + } + + bits = jazz16_bits = bits << 5; + + switch (mpu_base) + { + case 0x310: + bits |= 1; + break; + case 0x320: + bits |= 2; + break; + case 0x330: + bits |= 3; + break; + + default: + printk ("Jazz16: Invalid MIDI I/O port %x\n", mpu_base); + return 0; + } +/* + * Magic wake up sequence by writing to 0x201 (aka Joystick port) + */ + save_flags (flags); + cli (); + outb (0xAF, 0x201); + outb (0x50, 0x201); + outb (bits, 0x201); + restore_flags (flags); + + hw_config->name = "Jazz16"; + smw_midi_init (devc, hw_config); + + if (!sb_dsp_command (devc, 0xfb)) + return 0; + + if (!sb_dsp_command (devc, jazz_dma_bits[devc->dma8] | + (jazz_dma_bits[devc->dma16] << 4))) + return 0; + + if (!sb_dsp_command (devc, jazz_irq_bits[devc->irq] | + (jazz_irq_bits[irq] << 4))) + return 0; + + return 1; +} + +void +attach_sbmpu (struct address_info *hw_config) +{ +#if defined(CONFIG_MIDI) && defined(CONFIG_UART401) + attach_uart401 (hw_config); +#endif +} + +int +probe_sbmpu (struct address_info *hw_config) +{ +#if defined(CONFIG_MIDI) && defined(CONFIG_UART401) + sb_devc *devc = last_devc; + + if (last_devc == NULL) + return 0; + + last_devc = 0; + + if (hw_config->io_base <= 0) + return 0; + + if (check_region (hw_config->io_base, 4)) + { + printk ("sbmpu: I/O port conflict (%x)\n", hw_config->io_base); + return 0; + } + + switch (devc->model) + { + case MDL_SB16: + if (hw_config->io_base != 0x300 && hw_config->io_base != 0x330) + { + printk ("SB16: Invalid MIDI port %x\n", hw_config->irq); + return 0; + } + hw_config->name = "Sound Blaster 16"; + hw_config->irq = -devc->irq; + sb16_set_mpu_port(devc, hw_config); + break; + + case MDL_ESS: + if (hw_config->irq < 3 || hw_config->irq == devc->irq) + hw_config->irq = -devc->irq; + if (!ess_midi_init (devc, hw_config)) + return 0; + hw_config->name = "ESS ES1688"; + break; + + case MDL_JAZZ: + if (hw_config->irq < 3 || hw_config->irq == devc->irq) + hw_config->irq = -devc->irq; + if (!init_Jazz16_midi (devc, hw_config)) + return 0; + break; + + default: + return 0; + } + + return probe_uart401 (hw_config); +#else + return 0; +#endif +} + +void +unload_sbmpu (struct address_info *hw_config) +{ +#if defined(CONFIG_MIDI) && defined(CONFIG_UART401) + unload_uart401 (hw_config); +#endif +} +#else /* !CONFIG_MIDI */ + +void +unload_sbmpu (struct address_info *hw_config) +{ +} + +int +probe_sbmpu (struct address_info *hw_config) +{ + return 0; +} + +void +attach_sbmpu (struct address_info *hw_config) +{ +} +#endif + + +#endif diff -ur --new-file old/linux/drivers/sound/sb_dsp.c new/linux/drivers/sound/sb_dsp.c --- old/linux/drivers/sound/sb_dsp.c Fri Apr 12 08:49:43 1996 +++ new/linux/drivers/sound/sb_dsp.c Thu Jan 1 01:00:00 1970 @@ -1,1661 +0,0 @@ -/* - * sound/sb_dsp.c - * - * The low level driver for the SoundBlaster DSP chip (SB1.0 to 2.1, SB Pro). - */ -/* - * Copyright by Hannu Savolainen 1993-1996 - * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#include - -/* - * Modified: - * Hunyue Yau Jan 6 1994 - * Added code to support Sound Galaxy NX Pro - * - * JRA Gibson April 1995 - * Code added for MV ProSonic/Jazz 16 in 16 bit mode - */ - -#include "sound_config.h" - -#if defined(CONFIG_SB) - -#include "sb.h" -#include "sb_mixer.h" -#undef SB_TEST_IRQ - -int sbc_base = 0; -static int sbc_irq = 0, sbc_dma; -static int open_mode = 0; /* Read, write or both */ -int Jazz16_detected = 0; -int AudioDrive = 0; /* 1=ES1688 detected */ -static int ess_mpu_irq = 0; -int sb_no_recording = 0; -static int dsp_count = 0; -static int trigger_bits; -static int mpu_base = 0, mpu_irq = 0; -static int sb16_inited = 0; - -/* - * The DSP channel can be used either for input or output. Variable - * 'sb_irq_mode' will be set when the program calls read or write first time - * after open. Current version doesn't support mode changes without closing - * and reopening the device. Support for this feature may be implemented in a - * future version of this driver. - */ - -int sb_dsp_ok = 0; /* - - - * * * * Set to 1 after successful - * initialization * */ -static int midi_disabled = 0; -int sb_dsp_highspeed = 0; -int sbc_major = 0, sbc_minor = 0; -static int dsp_stereo = 0; -static int dsp_current_speed = DSP_DEFAULT_SPEED; -static int dsp_requested_speed = DSP_DEFAULT_SPEED; -static int sb16 = 0; -static int irq_verified = 0; - -int sb_midi_mode = NORMAL_MIDI; -int sb_midi_busy = 0; -int sb_dsp_busy = 0; - -volatile int sb_irq_mode = IMODE_NONE; -static volatile int irq_ok = 0; - -static int dma8 = 1; -static int dsp_16bit = 0; - -/* 16 bit support - */ - -static int dma16 = 1; - -static int dsp_set_bits (int arg); -static int initialize_ProSonic16 (void); - -/* end of 16 bit support - */ - -int sb_duplex_midi = 0; -static int my_dev = 0; - -volatile int sb_intr_active = 0; - -static int dsp_speed (int); -static int dsp_set_stereo (int mode); -static void sb_dsp_reset (int dev); -static void dsp_get_vers (struct address_info *hw_config); -int *sb_osp = NULL; - -#if defined(CONFIG_MIDI) || defined(CONFIG_AUDIO) - -/* - * Common code for the midi and pcm functions - */ - -int -sb_dsp_command (unsigned char val) -{ - int i; - unsigned long limit; - - limit = jiffies + HZ / 10; /* - * The timeout is 0.1 seconds - */ - - /* - * Note! the i<500000 is an emergency exit. The sb_dsp_command() is sometimes - * called while interrupts are disabled. This means that the timer is - * disabled also. However the timeout situation is a abnormal condition. - * Normally the DSP should be ready to accept commands after just couple of - * loops. - */ - - for (i = 0; i < 500000 && jiffies < limit; i++) - { - if ((inb (DSP_STATUS) & 0x80) == 0) - { - outb (val, DSP_COMMAND); - return 1; - } - } - - printk ("SoundBlaster: DSP Command(%x) Timeout.\n", val); - return 0; -} - -static int -ess_write (unsigned char reg, unsigned char data) -{ - /* Write a byte to an extended mode register of ES1688 */ - - if (!sb_dsp_command (reg)) - return 0; - - return sb_dsp_command (data); -} - -static int -ess_read (unsigned char reg) -{ -/* Read a byte from an extended mode register of ES1688 */ - - int i; - - if (!sb_dsp_command (0xc0)) /* Read register command */ - return -1; - - if (!sb_dsp_command (reg)) - return -1; - - for (i = 1000; i; i--) - { - if (inb (DSP_DATA_AVAIL) & 0x80) - return inb (DSP_READ); - } - - return -1; -} - -void -sbintr (int irq, void *dev_id, struct pt_regs *dummy) -{ - int status; - - if (sb16 && !AudioDrive) - { - unsigned char src = sb_getmixer (IRQ_STAT); /* Interrupt source register */ - - if (src & 3) - sb16_dsp_interrupt (irq); - -#ifdef CONFIG_MIDI - if (src & 4) - sb16midiintr (irq); /* - * SB MPU401 interrupt - */ -#endif - - if (!(src & 1)) - return; /* - * Not a DSP interrupt - */ - } - - status = inb (DSP_DATA_AVAIL); /* - * Clear interrupt - */ - if (sb_intr_active) - switch (sb_irq_mode) - { - case IMODE_OUTPUT: - if (!AudioDrive) - sb_intr_active = 0; - DMAbuf_outputintr (my_dev, 1); - break; - - case IMODE_INPUT: - if (!AudioDrive) - sb_intr_active = 0; - DMAbuf_inputintr (my_dev); - break; - - case IMODE_INIT: - sb_intr_active = 0; - irq_ok = 1; - break; - - case IMODE_MIDI: -#ifdef CONFIG_MIDI - sb_midi_interrupt (irq); -#endif - break; - - default: - printk ("SoundBlaster: Unexpected interrupt\n"); - } -} - -int -sb_get_irq (void) -{ - return 0; -} - -void -sb_free_irq (void) -{ -} - -int -sb_reset_dsp (void) -{ - int loopc; - - if (AudioDrive) - outb (3, DSP_RESET); /* Reset FIFO too */ - else - outb (1, DSP_RESET); - - tenmicrosec (sb_osp); - outb (0, DSP_RESET); - tenmicrosec (sb_osp); - tenmicrosec (sb_osp); - tenmicrosec (sb_osp); - - for (loopc = 0; loopc < 1000 && !(inb (DSP_DATA_AVAIL) & 0x80); loopc++); - - if (inb (DSP_READ) != 0xAA) - return 0; /* Sorry */ - - if (AudioDrive) - sb_dsp_command (0xc6); /* Enable extended mode */ - - return 1; -} - -#endif - -#ifdef CONFIG_AUDIO - -static void -dsp_speaker (char state) -{ - if (state) - sb_dsp_command (DSP_CMD_SPKON); - else - sb_dsp_command (DSP_CMD_SPKOFF); -} - -static int -ess_speed (int speed) -{ - int divider; - unsigned char bits = 0; - - if (speed < 4000) - speed = 4000; - else if (speed > 48000) - speed = 48000; - - if (speed > 22000) - { - bits = 0x80; - divider = 256 - (795500 + speed / 2) / speed; - dsp_current_speed = 795500 / (256 - divider); - } - else - { - divider = 128 - (397700 + speed / 2) / speed; - dsp_current_speed = 397700 / (128 - divider); - } - - bits |= (unsigned char) divider; - ess_write (0xa1, bits); - -/* - * Set filter divider register - */ - - speed = (speed * 9) / 20; /* Set filter rolloff to 90% of speed/2 */ - divider = 256 - 7160000 / (speed * 82); - ess_write (0xa2, divider); - - return dsp_current_speed; -} - -static int -dsp_speed (int speed) -{ - unsigned char tconst; - unsigned long flags; - int max_speed = 44100; - - dsp_requested_speed = speed; - - if (AudioDrive) - return ess_speed (speed); - - if (speed < 4000) - speed = 4000; - - /* - * Older SB models don't support higher speeds than 22050. - */ - - if (sbc_major < 2 || - (sbc_major == 2 && sbc_minor == 0)) - max_speed = 22050; - - /* - * SB models earlier than SB Pro have low limit for the input speed. - */ - if (open_mode != OPEN_WRITE) /* Recording is possible */ - if (sbc_major < 3) /* Limited input speed with these cards */ - if (sbc_major == 2 && sbc_minor > 0) - max_speed = 15000; - else - max_speed = 13000; - - if (speed > max_speed) - speed = max_speed; /* - * Invalid speed - */ - - /* Logitech SoundMan Games and Jazz16 cards can support 44.1kHz stereo */ -#if !defined (SM_GAMES) - /* - * Max. stereo speed is 22050 - */ - if (dsp_stereo && speed > 22050 && Jazz16_detected == 0 && AudioDrive == 0) - speed = 22050; -#endif - - if ((speed > 22050) && sb_midi_busy) - { - printk ("SB Warning: High speed DSP not possible simultaneously with MIDI output\n"); - speed = 22050; - } - - if (dsp_stereo) - speed *= 2; - - /* - * Now the speed should be valid - */ - - if (speed > 22050) - { /* - * High speed mode - */ - int tmp; - - tconst = (unsigned char) ((65536 - - ((256000000 + speed / 2) / speed)) >> 8); - sb_dsp_highspeed = 1; - - save_flags (flags); - cli (); - if (sb_dsp_command (0x40)) - sb_dsp_command (tconst); - restore_flags (flags); - - tmp = 65536 - (tconst << 8); - speed = (256000000 + tmp / 2) / tmp; - } - else - { - int tmp; - - sb_dsp_highspeed = 0; - tconst = (256 - ((1000000 + speed / 2) / speed)) & 0xff; - - save_flags (flags); - cli (); - if (sb_dsp_command (0x40)) /* - * Set time constant - */ - sb_dsp_command (tconst); - restore_flags (flags); - - tmp = 256 - tconst; - speed = (1000000 + tmp / 2) / tmp; - } - - if (dsp_stereo) - speed /= 2; - - dsp_current_speed = speed; - return speed; -} - -static int -dsp_set_stereo (int mode) -{ - dsp_stereo = 0; - - if (sbc_major < 3 || sb16) - return 0; /* - * Sorry no stereo - */ - - if (mode && sb_midi_busy) - { - printk ("SB Warning: Stereo DSP not possible simultaneously with MIDI output\n"); - return 0; - } - - dsp_stereo = !!mode; - dsp_speed (dsp_requested_speed); - return dsp_stereo; -} - -static unsigned long trg_buf; -static int trg_bytes; -static int trg_intrflag; -static int trg_restart; - -static void -sb_dsp_output_block (int dev, unsigned long buf, int nr_bytes, - int intrflag, int restart_dma) -{ - trg_buf = buf; - trg_bytes = nr_bytes; - trg_intrflag = intrflag; - trg_restart = restart_dma; - sb_irq_mode = IMODE_OUTPUT; -} - -static void -actually_output_block (int dev, unsigned long buf, int nr_bytes, - int intrflag, int restart_dma) -{ - unsigned long flags; - int count = nr_bytes; - - DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); - - sb_irq_mode = 0; - - if (audio_devs[dev]->dmachan1 > 3) - count >>= 1; - count--; - dsp_count = count; - - sb_irq_mode = IMODE_OUTPUT; - - if (AudioDrive) - { - short c = -nr_bytes; - - ess_write (0xa4, (unsigned char) ((unsigned short) c & 0xff)); - ess_write (0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff)); - - ess_write (0xb8, ess_read (0xb8) | 0x01); /* Go */ - } - else if (sb_dsp_highspeed) - { - save_flags (flags); - cli (); - if (sb_dsp_command (0x48)) /* - * High speed size - */ - { - sb_dsp_command ((unsigned char) (dsp_count & 0xff)); - sb_dsp_command ((unsigned char) ((dsp_count >> 8) & 0xff)); - sb_dsp_command (0x91); /* - * High speed 8 bit DAC - */ - } - else - printk ("SB Error: Unable to start (high speed) DAC\n"); - restore_flags (flags); - } - else - { - save_flags (flags); - cli (); - if (sb_dsp_command (0x14)) /* - * 8-bit DAC (DMA) - */ - { - sb_dsp_command ((unsigned char) (dsp_count & 0xff)); - sb_dsp_command ((unsigned char) ((dsp_count >> 8) & 0xff)); - } - else - printk ("SB Error: Unable to start DAC\n"); - restore_flags (flags); - } - sb_intr_active = 1; -} - -static void -sb_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, - int restart_dma) -{ - if (sb_no_recording) - { - return; - } - - trg_buf = buf; - trg_bytes = count; - trg_intrflag = intrflag; - trg_restart = restart_dma; - sb_irq_mode = IMODE_INPUT; -} - -static void -actually_start_input (int dev, unsigned long buf, int nr_bytes, int intrflag, - int restart_dma) -{ - unsigned long flags; - int count = nr_bytes; - - if (sb_no_recording) - { - return; - } - - /* - * Start a DMA input to the buffer pointed by dmaqtail - */ - - DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); - sb_irq_mode = 0; - - if (audio_devs[dev]->dmachan1 > 3) - count >>= 1; - count--; - dsp_count = count; - - sb_irq_mode = IMODE_INPUT; - - if (AudioDrive) - { - short c = -nr_bytes; - - ess_write (0xa4, (unsigned char) ((unsigned short) c & 0xff)); - ess_write (0xa5, (unsigned char) (((unsigned short) c >> 8) & 0xff)); - - ess_write (0xb8, ess_read (0xb8) | 0x01); /* Go */ - } - else if (sb_dsp_highspeed) - { - save_flags (flags); - cli (); - if (sb_dsp_command (0x48)) /* - * High speed size - */ - { - sb_dsp_command ((unsigned char) (dsp_count & 0xff)); - sb_dsp_command ((unsigned char) ((dsp_count >> 8) & 0xff)); - sb_dsp_command (0x99); /* - * High speed 8 bit ADC - */ - } - else - printk ("SB Error: Unable to start (high speed) ADC\n"); - restore_flags (flags); - } - else - { - save_flags (flags); - cli (); - if (sb_dsp_command (0x24)) /* - * 8-bit ADC (DMA) - */ - { - sb_dsp_command ((unsigned char) (dsp_count & 0xff)); - sb_dsp_command ((unsigned char) ((dsp_count >> 8) & 0xff)); - } - else - printk ("SB Error: Unable to start ADC\n"); - restore_flags (flags); - } - - sb_intr_active = 1; -} - -static void -sb_dsp_trigger (int dev, int bits) -{ - - if (!bits) - sb_dsp_command (0xd0); /* Halt DMA */ - else if (bits & sb_irq_mode) - { - switch (sb_irq_mode) - { - case IMODE_INPUT: - actually_start_input (my_dev, trg_buf, trg_bytes, - trg_intrflag, trg_restart); - break; - - case IMODE_OUTPUT: - actually_output_block (my_dev, trg_buf, trg_bytes, - trg_intrflag, trg_restart); - break; - } - } - - trigger_bits = bits; -} - -static void -dsp_cleanup (void) -{ - sb_intr_active = 0; -} - -static int -sb_dsp_prepare_for_input (int dev, int bsize, int bcount) -{ - if (sb_no_recording) - { - printk ("SB Error: This device doesn't support recording\n"); - return 0; - } - - dsp_cleanup (); - dsp_speaker (OFF); - dsp_speed (dsp_requested_speed); - - if (sbc_major == 3) /* - * SB Pro - */ - { - if (AudioDrive) - { - - ess_write (0xb8, 0x0e); /* Auto init DMA mode */ - ess_write (0xa8, (ess_read (0xa8) & ~0x04) | - (2 - dsp_stereo)); /* Mono/stereo */ - ess_write (0xb9, 2); /* Demand mode (2 bytes/xfer) */ - - if (!dsp_stereo) - { - if (dsp_16bit == 0) - { /* 8 bit mono */ - ess_write (0xb7, 0x51); - ess_write (0xb7, 0xd0); - } - else - { /* 16 bit mono */ - ess_write (0xb7, 0x71); - ess_write (0xb7, 0xf4); - } - } - else - { /* Stereo */ - if (!dsp_16bit) - { /* 8 bit stereo */ - ess_write (0xb7, 0x51); - ess_write (0xb7, 0x98); - } - else - { /* 16 bit stereo */ - ess_write (0xb7, 0x71); - ess_write (0xb7, 0xbc); - } - } - - ess_write (0xb1, (ess_read (0xb1) & 0x0f) | 0x50); - ess_write (0xb2, (ess_read (0xb2) & 0x0f) | 0x50); - } - else - { /* !AudioDrive */ - - /* Select correct dma channel - * for 16/8 bit access - */ - audio_devs[my_dev]->dmachan1 = - audio_devs[my_dev]->dmachan2 = - dsp_16bit ? dma16 : dma8; - if (dsp_stereo) - sb_dsp_command (dsp_16bit ? 0xac : 0xa8); - else - sb_dsp_command (dsp_16bit ? 0xa4 : 0xa0); - - } /* !AudioDrive */ - } - trigger_bits = 0; - return 0; -} - -static int -sb_dsp_prepare_for_output (int dev, int bsize, int bcount) -{ - dsp_cleanup (); - dsp_speaker (OFF); - dsp_speed (dsp_requested_speed); - - if (sbc_major == 3) /* SB Pro (at least ) */ - { - - if (AudioDrive) - { - - ess_write (0xb8, 4); /* Auto init DMA mode */ - ess_write (0xa8, ess_read (0xa8) | - (2 - dsp_stereo)); /* Mono/stereo */ - ess_write (0xb9, 2); /* Demand mode (2 bytes/xfer) */ - - if (!dsp_stereo) - { - if (dsp_16bit == 0) - { /* 8 bit mono */ - ess_write (0xb6, 0x80); - ess_write (0xb7, 0x51); - ess_write (0xb7, 0xd0); - } - else - { /* 16 bit mono */ - ess_write (0xb6, 0x00); - ess_write (0xb7, 0x71); - ess_write (0xb7, 0xf4); - } - } - else - { /* Stereo */ - if (!dsp_16bit) - { /* 8 bit stereo */ - ess_write (0xb6, 0x80); - ess_write (0xb7, 0x51); - ess_write (0xb7, 0x98); - } - else - { /* 16 bit stereo */ - ess_write (0xb6, 0x00); - ess_write (0xb7, 0x71); - ess_write (0xb7, 0xbc); - } - } - - ess_write (0xb1, (ess_read (0xb1) & 0x0f) | 0x50); - ess_write (0xb2, (ess_read (0xb2) & 0x0f) | 0x50); - } - else - { /* !AudioDrive */ - - /* 16 bit specific instructions (Jazz16) - */ - audio_devs[my_dev]->dmachan1 = - audio_devs[my_dev]->dmachan2 = - dsp_16bit ? dma16 : dma8; - if (Jazz16_detected != 2) /* SM Wave */ - sb_mixer_set_stereo (dsp_stereo); - if (dsp_stereo) - sb_dsp_command (dsp_16bit ? 0xac : 0xa8); - else - sb_dsp_command (dsp_16bit ? 0xa4 : 0xa0); - } /* !AudioDrive */ - - } - - trigger_bits = 0; - dsp_speaker (ON); - return 0; -} - -static void -sb_dsp_halt_xfer (int dev) -{ - if (AudioDrive) - sb_reset_dsp (); -} - -static int -verify_irq (void) -{ - irq_ok = 1; - return irq_ok; -} - -static int -sb_dsp_open (int dev, int mode) -{ - int retval; - - if (!sb_dsp_ok) - { - printk ("SB Error: SoundBlaster board not installed\n"); - return -ENXIO; - } - - if (sb_no_recording && mode & OPEN_READ) - { - printk ("SB Warning: Recording not supported by this device\n"); - } - - if (sb_intr_active || (sb_midi_busy && sb_midi_mode == UART_MIDI)) - { - printk ("SB: Audio device or MIDI already in use.\n"); - return -EBUSY; - } - - if (!sb_midi_busy) - sb_reset_dsp (); - - if (!irq_verified) - { - verify_irq (); - irq_verified = 1; - } - else if (!irq_ok) - printk ("SB Warning: Incorrect IRQ setting %d\n", - sbc_irq); - - retval = sb_get_irq (); - if (retval) - return retval; - - /* Allocate 8 bit dma - */ - audio_devs[my_dev]->dmachan1 = - audio_devs[my_dev]->dmachan2 = - dma8; - - /* Allocate 16 bit dma (jazz16) - */ - if (Jazz16_detected != 0) - if (dma16 != dma8) - { - if (sound_open_dma (dma16, "Jazz16 16 bit")) - { - sb_free_irq (); - /* DMAbuf_close_dma (dev); */ - return -EBUSY; - } - } - - sb_irq_mode = IMODE_NONE; - - sb_dsp_busy = 1; - open_mode = mode; - - return 0; -} - -static void -sb_dsp_close (int dev) -{ - /* Release 16 bit dma channel - */ - if (Jazz16_detected) - { - audio_devs[my_dev]->dmachan1 = - audio_devs[my_dev]->dmachan2 = - dma8; - - if (dma16 != dma8) - sound_close_dma (dma16); - } - - if (AudioDrive) - sb_reset_dsp (); - - /* DMAbuf_close_dma (dev); */ - sb_free_irq (); - /* sb_dsp_command (0xd4); */ - dsp_cleanup (); - dsp_speaker (OFF); - sb_dsp_busy = 0; - sb_dsp_highspeed = 0; - open_mode = 0; -} - -static int -dsp_set_bits (int arg) -{ - if (arg) - if (Jazz16_detected == 0 && AudioDrive == 0) - dsp_16bit = 0; - else - switch (arg) - { - case 8: - dsp_16bit = 0; - break; - case 16: - dsp_16bit = 1; - break; - default: - dsp_16bit = 0; - } - - return dsp_16bit ? 16 : 8; -} - -static int -sb_dsp_ioctl (int dev, unsigned int cmd, caddr_t arg, int local) -{ - switch (cmd) - { - case SOUND_PCM_WRITE_RATE: - if (local) - return dsp_speed ((long) arg); - return snd_ioctl_return ((int *) arg, dsp_speed (get_fs_long ((long *) arg))); - break; - - case SOUND_PCM_READ_RATE: - if (local) - return dsp_current_speed; - return snd_ioctl_return ((int *) arg, dsp_current_speed); - break; - - case SOUND_PCM_WRITE_CHANNELS: - if (local) - return dsp_set_stereo ((long) arg - 1) + 1; - return snd_ioctl_return ((int *) arg, dsp_set_stereo (get_fs_long ((long *) arg) - 1) + 1); - break; - - case SOUND_PCM_READ_CHANNELS: - if (local) - return dsp_stereo + 1; - return snd_ioctl_return ((int *) arg, dsp_stereo + 1); - break; - - case SNDCTL_DSP_STEREO: - if (local) - return dsp_set_stereo ((long) arg); - return snd_ioctl_return ((int *) arg, dsp_set_stereo (get_fs_long ((long *) arg))); - break; - - /* Word size specific cases here. - * SNDCTL_DSP_SETFMT=SOUND_PCM_WRITE_BITS - */ - case SNDCTL_DSP_SETFMT: - if (local) - return dsp_set_bits ((long) arg); - return snd_ioctl_return ((int *) arg, dsp_set_bits (get_fs_long ((long *) arg))); - break; - - case SOUND_PCM_READ_BITS: - if (local) - return dsp_16bit ? 16 : 8; - return snd_ioctl_return ((int *) arg, dsp_16bit ? 16 : 8); - break; - - case SOUND_PCM_WRITE_FILTER: - case SOUND_PCM_READ_FILTER: - return -EINVAL; - break; - - default:; - } - - return -EINVAL; -} - -static void -sb_dsp_reset (int dev) -{ - unsigned long flags; - - save_flags (flags); - cli (); - - sb_reset_dsp (); - dsp_speed (dsp_current_speed); - dsp_cleanup (); - - restore_flags (flags); -} - -#endif - - -/* - * Initialization of a Media Vision ProSonic 16 Soundcard. - * The function initializes a ProSonic 16 like PROS.EXE does for DOS. It sets - * the base address, the DMA-channels, interrupts and enables the joystickport. - * - * Also used by Jazz 16 (same card, different name) - * - * written 1994 by Rainer Vranken - * E-Mail: rvranken@polaris.informatik.uni-essen.de - */ - -unsigned int -get_sb_byte (void) -{ - int i; - - for (i = 1000; i; i--) - if (inb (DSP_DATA_AVAIL) & 0x80) - { - return inb (DSP_READ); - } - - return 0xffff; -} - -/* - * Logitech Soundman Wave detection and initialization by Hannu Savolainen. - * - * There is a microcontroller (8031) in the SM Wave card for MIDI emulation. - * it's located at address MPU_BASE+4. MPU_BASE+7 is a SM Wave specific - * control register for MC reset, SCSI, OPL4 and DSP (future expansion) - * address decoding. Otherwise the SM Wave is just a ordinary MV Jazz16 - * based soundcard. - */ - -static void -smw_putmem (int base, int addr, unsigned char val) -{ - unsigned long flags; - - save_flags (flags); - cli (); - - outb (addr & 0xff, base + 1); /* Low address bits */ - outb (addr >> 8, base + 2); /* High address bits */ - outb (val, base); /* Data */ - - restore_flags (flags); -} - -static unsigned char -smw_getmem (int base, int addr) -{ - unsigned long flags; - unsigned char val; - - save_flags (flags); - cli (); - - outb (addr & 0xff, base + 1); /* Low address bits */ - outb (addr >> 8, base + 2); /* High address bits */ - val = inb (base); /* Data */ - - restore_flags (flags); - return val; -} - -#ifdef SMW_MIDI0001_INCLUDED -#include "smw-midi0001.h" -#else -unsigned char *smw_ucode = NULL; -int smw_ucodeLen = 0; - -#endif - -static int -initialize_smw (int mpu_base) -{ - - int mp_base = mpu_base + 4; /* Microcontroller base */ - int i; - unsigned char control; - - - /* - * Reset the microcontroller so that the RAM can be accessed - */ - - control = inb (mpu_base + 7); - outb (control | 3, mpu_base + 7); /* Set last two bits to 1 (?) */ - outb ((control & 0xfe) | 2, mpu_base + 7); /* xxxxxxx0 resets the mc */ - - for (i = 0; i < 300; i++) /* Wait at least 1ms */ - tenmicrosec (sb_osp); - - outb (control & 0xfc, mpu_base + 7); /* xxxxxx00 enables RAM */ - - /* - * Detect microcontroller by probing the 8k RAM area - */ - smw_putmem (mp_base, 0, 0x00); - smw_putmem (mp_base, 1, 0xff); - tenmicrosec (sb_osp); - - if (smw_getmem (mp_base, 0) != 0x00 || smw_getmem (mp_base, 1) != 0xff) - { - printk ("\nSM Wave: No microcontroller RAM detected (%02x, %02x)\n", - smw_getmem (mp_base, 0), smw_getmem (mp_base, 1)); - return 0; /* No RAM */ - } - - /* - * There is RAM so assume it's really a SM Wave - */ - - if (smw_ucodeLen > 0) - { - if (smw_ucodeLen != 8192) - { - printk ("\nSM Wave: Invalid microcode (MIDI0001.BIN) length\n"); - return 1; - } - - /* - * Download microcode - */ - - for (i = 0; i < 8192; i++) - smw_putmem (mp_base, i, smw_ucode[i]); - - /* - * Verify microcode - */ - - for (i = 0; i < 8192; i++) - if (smw_getmem (mp_base, i) != smw_ucode[i]) - { - printk ("SM Wave: Microcode verification failed\n"); - return 0; - } - } - - control = 0; -#ifdef SMW_SCSI_IRQ - /* - * Set the SCSI interrupt (IRQ2/9, IRQ3 or IRQ10). The SCSI interrupt - * is disabled by default. - * - * Btw the Zilog 5380 SCSI controller is located at MPU base + 0x10. - */ - { - static unsigned char scsi_irq_bits[] = - {0, 0, 3, 1, 0, 0, 0, 0, 0, 3, 2, 0, 0, 0, 0, 0}; - - control |= scsi_irq_bits[SMW_SCSI_IRQ] << 6; - } -#endif - -#ifdef SMW_OPL4_ENABLE - /* - * Make the OPL4 chip visible on the PC bus at 0x380. - * - * There is no need to enable this feature since this driver - * doesn't support OPL4 yet. Also there is no RAM in SM Wave so - * enabling OPL4 is pretty useless. - */ - control |= 0x10; /* Uses IRQ12 if bit 0x20 == 0 */ - /* control |= 0x20; Uncomment this if you want to use IRQ7 */ -#endif - - outb (control | 0x03, mpu_base + 7); /* xxxxxx11 restarts */ - return 1; -} - -static int -initialize_ProSonic16 (void) -{ - int x; - static unsigned char int_translat[16] = - {0, 0, 2, 3, 0, 1, 0, 4, 0, 2, 5, 0, 0, 0, 0, 6}, dma_translat[8] = - {0, 1, 0, 2, 0, 3, 0, 4}; - - outb (0xAF, 0x201); /* ProSonic/Jazz16 wakeup */ - for (x = 0; x < 1000; ++x) /* wait 10 milliseconds */ - tenmicrosec (sb_osp); - outb (0x50, 0x201); - outb ((sbc_base & 0x70) | ((mpu_base & 0x30) >> 4), 0x201); - - if (sb_reset_dsp ()) - { /* OK. We have at least a SB */ - - /* Check the version number of ProSonic (I guess) */ - - if (!sb_dsp_command (0xFA)) - return 1; - if (get_sb_byte () != 0x12) - return 1; - - if (sb_dsp_command (0xFB) && /* set DMA-channels and Interrupts */ - sb_dsp_command ((dma_translat[dma16] << 4) | dma_translat[dma8]) && - sb_dsp_command ((int_translat[mpu_irq] << 4) | int_translat[sbc_irq])) - { - Jazz16_detected = 1; - - if (mpu_base != 0) - if (initialize_smw (mpu_base)) - Jazz16_detected = 2; - - sb_dsp_disable_midi (); - } - - return 1; /* There was at least a SB */ - } - return 0; /* No SB or ProSonic16 detected */ -} - -int -sb_dsp_detect (struct address_info *hw_config) -{ - if (sb_dsp_ok) - return 0; /* - * Already initialized - */ - - sbc_base = hw_config->io_base; - sbc_irq = hw_config->irq; - sbc_dma = hw_config->dma; - sb_osp = hw_config->osp; - dma8 = dma16 = hw_config->dma; - - if (sb_reset_dsp ()) - dsp_get_vers (hw_config); - else - sbc_major = 0; - - if (sbc_major == 3 || sbc_major == 0) - if (initialize_ProSonic16 ()) - return 1; - - if (!sb_reset_dsp ()) - return 0; - - return 1; /* - * Detected - */ -} - -#ifdef CONFIG_AUDIO -static struct audio_operations sb_dsp_operations = -{ - "SoundBlaster", - NOTHING_SPECIAL, - AFMT_U8, /* Just 8 bits. Poor old SB */ - NULL, - sb_dsp_open, - sb_dsp_close, - sb_dsp_output_block, - sb_dsp_start_input, - sb_dsp_ioctl, - sb_dsp_prepare_for_input, - sb_dsp_prepare_for_output, - sb_dsp_reset, - sb_dsp_halt_xfer, - NULL, /* local_qlen */ - NULL, /* copy_from_user */ - NULL, - NULL, - sb_dsp_trigger -}; - -#endif - -static void -ess_init (int ess_minor) /* ESS1688 Initialization */ -{ - unsigned char cfg, irq_bits = 0, dma_bits = 0; - - AudioDrive = 1; - - if (ess_minor >= 8) /* ESS1688 doesn't support SB MIDI */ - midi_disabled = 1; - - sb_reset_dsp (); /* Turn on extended mode */ - -/* - * Set IRQ configuration register - */ - - cfg = 0x50; /* Enable only DMA counter interrupt */ - - switch (sbc_irq) - { - case 2: - case 9: - irq_bits = 0; - break; - - case 5: - irq_bits = 1; - break; - - case 7: - irq_bits = 2; - break; - - case 10: - irq_bits = 3; - break; - - default: - irq_bits = 0; - cfg = 0x10; /* Disable all interrupts */ - printk ("\nESS1688: Invalid IRQ %d\n", sbc_irq); - } - - if (!ess_write (0xb1, cfg | (irq_bits << 2))) - printk ("\nESS1688: Failed to write to IRQ config register\n"); - -/* - * Set DMA configuration register - */ - - cfg = 0x50; /* Extended mode DMA enable */ - - if (sbc_dma > 3 || sbc_dma < 0 || sbc_dma == 2) - { - dma_bits = 0; - cfg = 0x00; /* Disable all DMA */ - printk ("\nESS1688: Invalid DMA %d\n", sbc_dma); - } - else - { - if (sbc_dma == 3) - dma_bits = 3; - else - dma_bits = sbc_dma + 1; - } - - if (!ess_write (0xb2, cfg | (dma_bits << 2))) - printk ("\nESS1688: Failed to write to DMA config register\n"); - -/* - * Enable joystick and OPL3 - */ - - cfg = sb_getmixer (0x40); - sb_setmixer (0x40, cfg | 0x03); -} - -#ifdef CONFIG_MIDI -void -ess_midi_init (struct address_info *hw_config) /* called from sb16_midi.c */ -{ - unsigned char cfg, tmp; - - cfg = sb_getmixer (0x40) & 0x03; - - tmp = (hw_config->io_base & 0x0f0) >> 4; - - if (tmp > 3) - { - sb_setmixer (0x40, cfg); - return; - } - - cfg |= tmp << 3; - - tmp = 1; /* MPU enabled without interrupts */ - - switch (hw_config->irq) - { - case 9: - tmp = 0x4; - break; - case 5: - tmp = 0x5; - break; - case 7: - tmp = 0x6; - break; - case 10: - tmp = 0x7; - break; - } - - cfg |= tmp << 5; - - if (tmp != 1) - { - ess_mpu_irq = hw_config->irq; - - if (snd_set_irq_handler (ess_mpu_irq, sbmidiintr, "ES1688 MIDI", sb_osp) < 0) - printk ("ES1688: Can't allocate IRQ%d\n", ess_mpu_irq); - } - - sb_setmixer (0x40, cfg); -} -#endif - -void -Jazz16_midi_init (struct address_info *hw_config) -{ - extern void smw_mixer_init (void); - extern void sb_mixer_reset (void); - - mpu_base = hw_config->io_base; - mpu_irq = hw_config->irq; - - initialize_ProSonic16 (); - - smw_mixer_init (); - sb_mixer_reset (); -} - -void -Jazz16_set_dma16 (int dma) -{ - dma16 = dma; - -/* Allocate 16 bit dma (Jazz16) - */ - if (dma16 != dma8) - { - if (sound_alloc_dma (dma16, "Jazz16 16 bit")) - { - printk ("Jazz16: Can't allocate 16 bit DMA channel\n"); - Jazz16_detected = 0; - return; - } - } - initialize_ProSonic16 (); -} - -static void -dsp_get_vers (struct address_info *hw_config) -{ - int i; - - unsigned long flags; - - save_flags (flags); - cli (); - sb_osp = hw_config->osp; - sbc_major = sbc_minor = 0; - sb_dsp_command (0xe1); /* Get version */ - - for (i = 100000; i; i--) - { - if (inb (DSP_DATA_AVAIL) & 0x80) - { - if (sbc_major == 0) - sbc_major = inb (DSP_READ); - else - { - sbc_minor = inb (DSP_READ); - break; - } - } - } - restore_flags (flags); -} - -long -sb_dsp_init (long mem_start, struct address_info *hw_config) -{ - int i; - int ess_major = 0, ess_minor = 0; - - int mixer_type = 0; - - if (sbc_major == 0) - dsp_get_vers (hw_config); - - if (sbc_major == 0) - { - sb_reset_dsp (); - dsp_get_vers (hw_config); - } - - if (sbc_major == 0) - { - printk ("\n\nFailed to get SB version (%x) - possible I/O conflict?\n\n", - inb (DSP_DATA_AVAIL)); - sbc_major = 1; - } - - if (sbc_major == 2 || sbc_major == 3) - sb_duplex_midi = 1; - - if (sbc_major == 4) - sb16 = 1; - - if (sbc_major == 3 && sbc_minor == 1) - { - -/* - * Try to detect ESS chips. - */ - - sb_dsp_command (0xe7); /* - * Return identification bytes. - */ - - for (i = 1000; i; i--) - { - if (inb (DSP_DATA_AVAIL) & 0x80) - { /* - * wait for Data Ready - */ - if (ess_major == 0) - ess_major = inb (DSP_READ); - else - { - ess_minor = inb (DSP_READ); - break; - } - } - } - } - - if (snd_set_irq_handler (sbc_irq, sbintr, "SoundBlaster", sb_osp) < 0) - printk ("sb_dsp: Can't allocate IRQ\n");; - -#ifdef CONFIG_AUDIO - if (sbc_major >= 3) - { - if (Jazz16_detected) - { - if (Jazz16_detected == 2) - sprintf (sb_dsp_operations.name, "SoundMan Wave %d.%d", sbc_major, sbc_minor); - else - sprintf (sb_dsp_operations.name, "MV Jazz16 %d.%d", sbc_major, sbc_minor); - sb_dsp_operations.format_mask |= AFMT_S16_LE; /* Hurrah, 16 bits */ - } - else -#ifdef __SGNXPRO__ - if (mixer_type == 2) - { - sprintf (sb_dsp_operations.name, "Sound Galaxy NX Pro %d.%d", sbc_major, sbc_minor); - } - else -#endif - - if (sbc_major == 4) - { - sprintf (sb_dsp_operations.name, "SoundBlaster 16 %d.%d", sbc_major, sbc_minor); - } - else if (ess_major != 0) - { - if (ess_major == 0x48 && (ess_minor & 0xf0) == 0x80) - sprintf (sb_dsp_operations.name, "ESS ES488 AudioDrive (rev %d)", - ess_minor & 0x0f); - else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80) - { - sprintf (sb_dsp_operations.name, - "ESS ES1688 AudioDrive (rev %d)", - ess_minor & 0x0f); - sb_dsp_operations.format_mask |= AFMT_S16_LE; - ess_init (ess_minor); - } - } - else - { - sprintf (sb_dsp_operations.name, "SoundBlaster Pro %d.%d", sbc_major, sbc_minor); - } - } - else - { - sprintf (sb_dsp_operations.name, "SoundBlaster %d.%d", sbc_major, sbc_minor); - } - - conf_printf (sb_dsp_operations.name, hw_config); - - if (sbc_major >= 3) - mixer_type = sb_mixer_init (sbc_major); - - if (!sb16) - if (num_audiodevs < MAX_AUDIO_DEV) - { - audio_devs[my_dev = num_audiodevs++] = &sb_dsp_operations; - - if (AudioDrive) - audio_devs[my_dev]->flags |= DMA_AUTOMODE; - - audio_devs[my_dev]->buffsize = DSP_BUFFSIZE; - dma8 = audio_devs[my_dev]->dmachan1 = hw_config->dma; - dma16 = audio_devs[my_dev]->dmachan2 = hw_config->dma; - if (sound_alloc_dma (hw_config->dma, "SoundBlaster")) - printk ("sb_dsp.c: Can't allocate DMA channel\n"); - } - else - printk ("SB: Too many DSP devices available\n"); -#else - conf_printf ("SoundBlaster (configured without audio support)", hw_config); -#endif - -#ifdef CONFIG_MIDI - if (!midi_disabled && !sb16) /* - * Midi don't work in the SB emulation mode * - * of PAS, SB16 has better midi interface - */ - sb_midi_init (sbc_major); -#endif - - sb_dsp_ok = 1; - sb_reset_dsp (); - - if (sb16 || hw_config->dma2 >= 0) - { - if (sb16_dsp_detect (hw_config)) - { - sb16_inited = 1; - return sb16_dsp_init (mem_start, hw_config); - } - } - return mem_start; -} - -void -sb_dsp_unload (struct address_info *hw_config) -{ - sound_free_dma (dma8); - - /* Free 16 bit dma (Jazz16) - */ - if (Jazz16_detected != 0) - if (dma16 != dma8) - { - sound_free_dma (dma16); - } - snd_release_irq (sbc_irq); - - if (AudioDrive && ess_mpu_irq) - { - snd_release_irq (ess_mpu_irq); - } - - if (sb16_inited) - unload_sb16 (hw_config); -} - -void -sb_dsp_disable_midi (void) -{ - midi_disabled = 1; -} - - -#endif diff -ur --new-file old/linux/drivers/sound/sb_midi.c new/linux/drivers/sound/sb_midi.c --- old/linux/drivers/sound/sb_midi.c Fri Apr 12 08:49:43 1996 +++ new/linux/drivers/sound/sb_midi.c Wed Aug 7 11:31:22 1996 @@ -1,37 +1,21 @@ /* * sound/sb_dsp.c * - * The low level driver for the SoundBlaster DS chips. + * The low level driver for the Sound Blaster DS chips. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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 "sound_config.h" -#if defined(CONFIG_SB) && defined(CONFIG_MIDI) +#if defined(CONFIG_SBDSP) && defined(CONFIG_MIDI) #include "sb.h" #undef SB_TEST_IRQ @@ -44,27 +28,6 @@ * future version of this driver. */ -extern int sb_dsp_ok; /* Set to 1 after successful initialization */ -extern int sbc_base; - -extern int sb_midi_mode; -extern int sb_midi_busy; /* - - - * * * * 1 if the process has output to MIDI - * - */ -extern int sb_dsp_busy; -extern int sb_dsp_highspeed; - -extern volatile int sb_irq_mode; -extern int sb_duplex_midi; -extern int sb_intr_active; -int input_opened = 0; -static int my_dev; - -extern int *sb_osp; - void (*midi_input_intr) (int dev, unsigned char data); static int @@ -73,100 +36,70 @@ void (*output) (int dev) ) { - int ret; + sb_devc *devc = midi_devs[dev]->devc; + unsigned long flags; + + if (devc == NULL) + return -(ENXIO); - if (!sb_dsp_ok) + save_flags (flags); + cli (); + if (devc->opened) { - printk ("SB Error: MIDI hardware not installed\n"); - return -ENXIO; + restore_flags (flags); + return -(EBUSY); } + devc->opened = 1; + restore_flags (flags); - if (sb_midi_busy) - return -EBUSY; + devc->irq_mode = IMODE_MIDI; - if (mode != OPEN_WRITE && !sb_duplex_midi) - { - if (num_midis == 1) - printk ("SoundBlaster: Midi input not currently supported\n"); - return -EPERM; - } + sb_dsp_reset (devc); - sb_midi_mode = NORMAL_MIDI; - if (mode != OPEN_WRITE) + if (!sb_dsp_command (devc, 0x35)) /* Start MIDI UART mode */ { - if (sb_dsp_busy || sb_intr_active) - return -EBUSY; - sb_midi_mode = UART_MIDI; + devc->opened = 0; + return -(EIO); } - if (sb_dsp_highspeed) - { - printk ("SB Error: Midi output not possible during stereo or high speed audio\n"); - return -EBUSY; - } + devc->intr_active = 1; - if (sb_midi_mode == UART_MIDI) + if (mode & OPEN_READ) { - sb_irq_mode = IMODE_MIDI; - - sb_reset_dsp (); - - if (!sb_dsp_command (0x35)) - return -EIO; /* - * Enter the UART mode - */ - sb_intr_active = 1; - - if ((ret = sb_get_irq ()) < 0) - { - sb_reset_dsp (); - return 0; /* - * IRQ not free - */ - } - input_opened = 1; - midi_input_intr = input; + devc->input_opened = 1; + devc->midi_input_intr = input; } - sb_midi_busy = 1; - return 0; } static void sb_midi_close (int dev) { - if (sb_midi_mode == UART_MIDI) - { - sb_reset_dsp (); /* - * The only way to kill the UART mode - */ - sb_free_irq (); - } - sb_intr_active = 0; - sb_midi_busy = 0; - input_opened = 0; + sb_devc *devc = midi_devs[dev]->devc; + unsigned long flags; + + if (devc == NULL) + return; + + save_flags (flags); + cli (); + sb_dsp_reset (devc); + devc->intr_active = 0; + devc->input_opened = 0; + devc->opened = 0; + restore_flags (flags); } static int sb_midi_out (int dev, unsigned char midi_byte) { - unsigned long flags; + sb_devc *devc = midi_devs[dev]->devc; - if (sb_midi_mode == NORMAL_MIDI) - { - save_flags (flags); - cli (); - if (sb_dsp_command (0x38)) - sb_dsp_command (midi_byte); - else - printk ("SB Error: Unable to send a MIDI byte\n"); - restore_flags (flags); - } - else - sb_dsp_command (midi_byte); /* - * UART write - */ + if (devc == NULL) + return -(ENXIO); + + sb_dsp_command (devc, midi_byte); return 1; } @@ -174,54 +107,54 @@ static int sb_midi_start_read (int dev) { - if (sb_midi_mode != UART_MIDI) - { - printk ("SoundBlaster: MIDI input not implemented.\n"); - return -EPERM; - } return 0; } static int sb_midi_end_read (int dev) { - if (sb_midi_mode == UART_MIDI) - { - sb_reset_dsp (); - sb_intr_active = 0; - } + sb_devc *devc = midi_devs[dev]->devc; + + if (devc == NULL) + return -(ENXIO); + + sb_dsp_reset (devc); + devc->intr_active = 0; return 0; } static int sb_midi_ioctl (int dev, unsigned cmd, caddr_t arg) { - return -EPERM; + return -(EPERM); } void -sb_midi_interrupt (int dummy) +sb_midi_interrupt (sb_devc * devc) { unsigned long flags; unsigned char data; + if (devc == NULL) + return; + save_flags (flags); cli (); data = inb (DSP_READ); - if (input_opened) - midi_input_intr (my_dev, data); + if (devc->input_opened) + devc->midi_input_intr (devc->my_mididev, data); restore_flags (flags); } -#define MIDI_SYNTH_NAME "SoundBlaster Midi" +#define MIDI_SYNTH_NAME "Sound Blaster Midi" #define MIDI_SYNTH_CAPS 0 #include "midi_synth.h" static struct midi_operations sb_midi_operations = { - {"SoundBlaster", 0, 0, SNDCARD_SB}, + {"Sound Blaster", 0, 0, SNDCARD_SB}, &std_midi_synth, {0}, sb_midi_open, @@ -230,21 +163,18 @@ sb_midi_out, sb_midi_start_read, sb_midi_end_read, - NULL, /* - * Kick - */ - NULL, /* - * command - */ - NULL, /* - * buffer_status - */ + NULL, + NULL, + NULL, NULL }; void -sb_midi_init (int model) +sb_dsp_midi_init (sb_devc * devc) { + if (devc->model < 2) /* No MIDI support for SB 1.x */ + return; + if (num_midis >= MAX_MIDI_DEV) { printk ("Sound: Too many midi devices detected\n"); @@ -252,8 +182,42 @@ } std_midi_synth.midi_dev = num_midis; - my_dev = num_midis; - midi_devs[num_midis++] = &sb_midi_operations; + devc->my_mididev = num_midis; + + std_midi_synth.midi_dev = devc->my_mididev = num_midis; + + + midi_devs[num_midis] = (struct midi_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct midi_operations))); + + if (sound_nblocks < 1024) + sound_nblocks++;; + if (midi_devs[num_midis] == NULL) + { + printk ("sb MIDI: Failed to allocate memory\n"); + return; + } + + memcpy ((char *) midi_devs[num_midis], (char *) &sb_midi_operations, + sizeof (struct midi_operations)); + + midi_devs[num_midis]->devc = devc; + + + midi_devs[num_midis]->converter = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct synth_operations))); + + if (sound_nblocks < 1024) + sound_nblocks++;; + + if (midi_devs[num_midis]->converter == NULL) + { + printk ("sb MIDI: Failed to allocate memory\n"); + return; + } + + memcpy ((char *) midi_devs[num_midis]->converter, (char *) &std_midi_synth, + sizeof (struct synth_operations)); + + num_midis++; } #endif diff -ur --new-file old/linux/drivers/sound/sb_mixer.c new/linux/drivers/sound/sb_mixer.c --- old/linux/drivers/sound/sb_mixer.c Sun Mar 24 21:50:21 1996 +++ new/linux/drivers/sound/sb_mixer.c Sun Aug 18 09:46:49 1996 @@ -2,251 +2,100 @@ /* * sound/sb_mixer.c * - * The low level mixer driver for the SoundBlaster Pro and SB16 cards. + * The low level mixer driver for the Sound Blaster compatible cards. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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 -/* - * Modified: - * Hunyue Yau Jan 6 1994 - * Added code to support the Sound Galaxy NX Pro mixer. - * - */ #include "sound_config.h" -#if defined(CONFIG_SB) +#if defined(CONFIG_SBDSP) #define __SB_MIXER_C__ #include "sb.h" #include "sb_mixer.h" -#undef SB_TEST_IRQ - -extern int sbc_base; -extern int Jazz16_detected; -extern int *sb_osp; -extern int AudioDrive; - -static int mixer_initialized = 0; - -static int supported_rec_devices; -static int supported_devices; -static int recmask = 0; -static int mixer_model; -static int mixer_caps; -static mixer_tab *iomap; - -void -sb_setmixer (unsigned int port, unsigned int value) -{ - unsigned long flags; - - save_flags (flags); - cli (); - outb ((unsigned char) (port & 0xff), MIXER_ADDR); /* - * Select register - */ - tenmicrosec (sb_osp); - outb ((unsigned char) (value & 0xff), MIXER_DATA); - tenmicrosec (sb_osp); - restore_flags (flags); -} - -int -sb_getmixer (unsigned int port) -{ - int val; - unsigned long flags; - - save_flags (flags); - cli (); - outb ((unsigned char) (port & 0xff), MIXER_ADDR); /* - * Select register - */ - tenmicrosec (sb_osp); - val = inb (MIXER_DATA); - tenmicrosec (sb_osp); - restore_flags (flags); - return val; -} +void sb_mixer_reset (sb_devc * devc); void -sb_mixer_set_stereo (int mode) +sb_mixer_set_stereo (sb_devc * devc, int mode) { - if (!mixer_initialized) - return; - - sb_setmixer (OUT_FILTER, ((sb_getmixer (OUT_FILTER) & ~STEREO_DAC) - | (mode ? STEREO_DAC : MONO_DAC))); + sb_setmixer (devc, OUT_FILTER, ((sb_getmixer (devc, OUT_FILTER) & ~STEREO_DAC) + | (mode ? STEREO_DAC : MONO_DAC))); } -/* - * Returns: - * 0 No mixer detected. - * 1 Only a plain Sound Blaster Pro style mixer detected. - * 2 The Sound Galaxy NX Pro mixer detected. - */ static int -detect_mixer (void) +detect_mixer (sb_devc * devc) { -#ifdef __SGNXPRO__ - int oldbass, oldtreble; - extern int sbc_major; - -#endif - int retcode = 1; - /* * Detect the mixer by changing parameters of two volume channels. If the * values read back match with the values written, the mixer is there (is * it?) */ - sb_setmixer (FM_VOL, 0xff); - sb_setmixer (VOC_VOL, 0x33); + sb_setmixer (devc, FM_VOL, 0xff); + sb_setmixer (devc, VOC_VOL, 0x33); - if (sb_getmixer (FM_VOL) != 0xff) - return 0; /* - * No match - */ - if (sb_getmixer (VOC_VOL) != 0x33) + if (sb_getmixer (devc, FM_VOL) != 0xff) + return 0; + if (sb_getmixer (devc, VOC_VOL) != 0x33) return 0; -#ifdef __SGNXPRO__ - /* Attempt to detect the SG NX Pro by check for valid bass/treble - * registers. - */ - oldbass = sb_getmixer (BASS_LVL); - oldtreble = sb_getmixer (TREBLE_LVL); - - sb_setmixer (BASS_LVL, 0xaa); - sb_setmixer (TREBLE_LVL, 0x55); - - if ((sb_getmixer (BASS_LVL) != 0xaa) || - (sb_getmixer (TREBLE_LVL) != 0x55)) - { - retcode = 1; /* 1 == Only SB Pro detected */ - } - else - retcode = 2; /* 2 == SG NX Pro detected */ - /* Restore register in either case since SG NX Pro has EEPROM with - * 'preferred' values stored. - */ - sb_setmixer (BASS_LVL, oldbass); - sb_setmixer (TREBLE_LVL, oldtreble); - - /* - * If the SB version is 3.X (SB Pro), assume we have a SG NX Pro 16. - * In this case it's good idea to disable the Disney Sound Source - * compatibility mode. It's useless and just causes noise every time the - * LPT-port is accessed. - * - * Also place the card into WSS mode. - */ - if (sbc_major == 3) - { - outb (0x01, sbc_base + 0x1c); - outb (0x00, sbc_base + 0x1a); - } - -#endif - return retcode; + return 1; } static void -change_bits (unsigned char *regval, int dev, int chn, int newval) +change_bits (sb_devc * devc, unsigned char *regval, int dev, int chn, int newval) { unsigned char mask; int shift; - mask = (1 << (*iomap)[dev][chn].nbits) - 1; - newval = (int) ((newval * mask) + 50) / 100; /* - * Scale it - */ + mask = (1 << (*devc->iomap)[dev][chn].nbits) - 1; + newval = (int) ((newval * mask) + 50) / 100; /* Scale */ - shift = (*iomap)[dev][chn].bitoffs - (*iomap)[dev][LEFT_CHN].nbits + 1; + shift = (*devc->iomap)[dev][chn].bitoffs - (*devc->iomap)[dev][LEFT_CHN].nbits + 1; - *regval &= ~(mask << shift); /* - * Filter out the previous value - */ - *regval |= (newval & mask) << shift; /* - * Set the new value - */ + *regval &= ~(mask << shift); /* Mask out previous value */ + *regval |= (newval & mask) << shift; /* Set the new value */ } static int -sb_mixer_get (int dev) +sb_mixer_get (sb_devc * devc, int dev) { - if (!((1 << dev) & supported_devices)) - return -EINVAL; + if (!((1 << dev) & devc->supported_devices)) + return -(EINVAL); - return levels[dev]; + return devc->levels[dev]; } -static char smw_mix_regs[] = /* Left mixer registers */ -{ - 0x0b, /* SOUND_MIXER_VOLUME */ - 0x0d, /* SOUND_MIXER_BASS */ - 0x0d, /* SOUND_MIXER_TREBLE */ - 0x05, /* SOUND_MIXER_SYNTH */ - 0x09, /* SOUND_MIXER_PCM */ - 0x00, /* SOUND_MIXER_SPEAKER */ - 0x03, /* SOUND_MIXER_LINE */ - 0x01, /* SOUND_MIXER_MIC */ - 0x07, /* SOUND_MIXER_CD */ - 0x00, /* SOUND_MIXER_IMIX */ - 0x00, /* SOUND_MIXER_ALTPCM */ - 0x00, /* SOUND_MIXER_RECLEV */ - 0x00, /* SOUND_MIXER_IGAIN */ - 0x00, /* SOUND_MIXER_OGAIN */ - 0x00, /* SOUND_MIXER_LINE1 */ - 0x00, /* SOUND_MIXER_LINE2 */ - 0x00 /* SOUND_MIXER_LINE3 */ -}; - void -smw_mixer_init (void) +smw_mixer_init (sb_devc * devc) { int i; - sb_setmixer (0x00, 0x18); /* Mute unused (Telephone) line */ - sb_setmixer (0x10, 0x38); /* Config register 2 */ + sb_setmixer (devc, 0x00, 0x18); /* Mute unused (Telephone) line */ + sb_setmixer (devc, 0x10, 0x38); /* Config register 2 */ - supported_devices = 0; + devc->supported_devices = 0; for (i = 0; i < sizeof (smw_mix_regs); i++) if (smw_mix_regs[i] != 0) - supported_devices |= (1 << i); + devc->supported_devices |= (1 << i); - supported_rec_devices = supported_devices & + devc->supported_rec_devices = devc->supported_devices & ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_PCM | SOUND_MASK_VOLUME); + + sb_mixer_reset (devc); } static int -smw_mixer_set (int dev, int value) +smw_mixer_set (sb_devc * devc, int dev, int value) { int left = value & 0x000000ff; int right = (value & 0x0000ff00) >> 8; @@ -258,47 +107,47 @@ right = 100; if (dev > 31) - return -EINVAL; + return -(EINVAL); - if (!(supported_devices & (1 << dev))) /* Not supported */ - return -EINVAL; + if (!(devc->supported_devices & (1 << dev))) /* Not supported */ + return -(EINVAL); switch (dev) { case SOUND_MIXER_VOLUME: - sb_setmixer (0x0b, 96 - (96 * left / 100)); /* 96=mute, 0=max */ - sb_setmixer (0x0c, 96 - (96 * right / 100)); + sb_setmixer (devc, 0x0b, 96 - (96 * left / 100)); /* 96=mute, 0=max */ + sb_setmixer (devc, 0x0c, 96 - (96 * right / 100)); break; case SOUND_MIXER_BASS: case SOUND_MIXER_TREBLE: - levels[dev] = left | (right << 8); + devc->levels[dev] = left | (right << 8); /* Set left bass and treble values */ - val = ((levels[SOUND_MIXER_TREBLE] & 0xff) * 16 / (unsigned) 100) << 4; - val |= ((levels[SOUND_MIXER_BASS] & 0xff) * 16 / (unsigned) 100) & 0x0f; - sb_setmixer (0x0d, val); + val = ((devc->levels[SOUND_MIXER_TREBLE] & 0xff) * 16 / (unsigned) 100) << 4; + val |= ((devc->levels[SOUND_MIXER_BASS] & 0xff) * 16 / (unsigned) 100) & 0x0f; + sb_setmixer (devc, 0x0d, val); /* Set right bass and treble values */ - val = (((levels[SOUND_MIXER_TREBLE] >> 8) & 0xff) * 16 / (unsigned) 100) << 4; - val |= (((levels[SOUND_MIXER_BASS] >> 8) & 0xff) * 16 / (unsigned) 100) & 0x0f; - sb_setmixer (0x0e, val); + val = (((devc->levels[SOUND_MIXER_TREBLE] >> 8) & 0xff) * 16 / (unsigned) 100) << 4; + val |= (((devc->levels[SOUND_MIXER_BASS] >> 8) & 0xff) * 16 / (unsigned) 100) & 0x0f; + sb_setmixer (devc, 0x0e, val); break; default: reg = smw_mix_regs[dev]; if (reg == 0) - return -EINVAL; - sb_setmixer (reg, (24 - (24 * left / 100)) | 0x20); /* 24=mute, 0=max */ - sb_setmixer (reg + 1, (24 - (24 * right / 100)) | 0x40); + return -(EINVAL); + sb_setmixer (devc, reg, (24 - (24 * left / 100)) | 0x20); /* 24=mute, 0=max */ + sb_setmixer (devc, reg + 1, (24 - (24 * right / 100)) | 0x40); } - levels[dev] = left | (right << 8); + devc->levels[dev] = left | (right << 8); return left | (right << 8); } static int -sb_mixer_set (int dev, int value) +sb_mixer_set (sb_devc * devc, int dev, int value) { int left = value & 0x000000ff; int right = (value & 0x0000ff00) >> 8; @@ -306,8 +155,8 @@ int regoffs; unsigned char val; - if (Jazz16_detected == 2) - return smw_mixer_set (dev, value); + if (devc->model == MDL_SMW) + return smw_mixer_set (devc, dev, value); if (left > 100) left = 100; @@ -315,67 +164,70 @@ right = 100; if (dev > 31) - return -EINVAL; + return -(EINVAL); - if (!(supported_devices & (1 << dev))) /* + if (!(devc->supported_devices & (1 << dev))) /* * Not supported */ - return -EINVAL; + return -(EINVAL); - regoffs = (*iomap)[dev][LEFT_CHN].regno; + regoffs = (*devc->iomap)[dev][LEFT_CHN].regno; if (regoffs == 0) - return -EINVAL; + return -(EINVAL); - val = sb_getmixer (regoffs); - change_bits (&val, dev, LEFT_CHN, left); + val = sb_getmixer (devc, regoffs); + change_bits (devc, &val, dev, LEFT_CHN, left); - levels[dev] = left | (left << 8); + devc->levels[dev] = left | (left << 8); - if ((*iomap)[dev][RIGHT_CHN].regno != regoffs) /* + if ((*devc->iomap)[dev][RIGHT_CHN].regno != regoffs) /* * Change register */ { - sb_setmixer (regoffs, val); /* - * Save the old one - */ - regoffs = (*iomap)[dev][RIGHT_CHN].regno; + sb_setmixer (devc, regoffs, val); /* + * Save the old one + */ + regoffs = (*devc->iomap)[dev][RIGHT_CHN].regno; if (regoffs == 0) return left | (left << 8); /* * Just left channel present */ - val = sb_getmixer (regoffs); /* - * Read the new one - */ + val = sb_getmixer (devc, regoffs); /* + * Read the new one + */ } - change_bits (&val, dev, RIGHT_CHN, right); + change_bits (devc, &val, dev, RIGHT_CHN, right); - sb_setmixer (regoffs, val); + sb_setmixer (devc, regoffs, val); - levels[dev] = left | (right << 8); + devc->levels[dev] = left | (right << 8); return left | (right << 8); } static void -set_recsrc (int src) +set_recsrc (sb_devc * devc, int src) { - sb_setmixer (RECORD_SRC, (sb_getmixer (RECORD_SRC) & ~7) | (src & 0x7)); + sb_setmixer (devc, RECORD_SRC, (sb_getmixer (devc, RECORD_SRC) & ~7) | (src & 0x7)); } static int -set_recmask (int mask) +set_recmask (sb_devc * devc, int mask) { int devmask, i; unsigned char regimageL, regimageR; - devmask = mask & supported_rec_devices; + devmask = mask & devc->supported_rec_devices; - switch (mixer_model) + switch (devc->model) { - case 3: + case MDL_SBPRO: + case MDL_ESS: + case MDL_JAZZ: + case MDL_SMW: if (devmask != SOUND_MASK_MIC && devmask != SOUND_MASK_LINE && @@ -384,7 +236,7 @@ * More than one devices selected. Drop the * * previous selection */ - devmask &= ~recmask; + devmask &= ~devc->recmask; } if (devmask != SOUND_MASK_MIC && @@ -398,33 +250,33 @@ } - if (devmask ^ recmask) /* - * Input source changed - */ + if (devmask ^ devc->recmask) /* + * Input source changed + */ { switch (devmask) { case SOUND_MASK_MIC: - set_recsrc (SRC_MIC); + set_recsrc (devc, SRC__MIC); break; case SOUND_MASK_LINE: - set_recsrc (SRC_LINE); + set_recsrc (devc, SRC__LINE); break; case SOUND_MASK_CD: - set_recsrc (SRC_CD); + set_recsrc (devc, SRC__CD); break; default: - set_recsrc (SRC_MIC); + set_recsrc (devc, SRC__MIC); } } break; - case 4: + case MDL_SB16: if (!devmask) devmask = SOUND_MASK_MIC; @@ -435,159 +287,155 @@ regimageL |= sb16_recmasks_L[i]; regimageR |= sb16_recmasks_R[i]; } - sb_setmixer (SB16_IMASK_L, regimageL); - sb_setmixer (SB16_IMASK_R, regimageR); + sb_setmixer (devc, SB16_IMASK_L, regimageL); + sb_setmixer (devc, SB16_IMASK_R, regimageR); break; } - recmask = devmask; - return recmask; + devc->recmask = devmask; + return devc->recmask; } static int sb_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) { + sb_devc *devc = mixer_devs[dev]->devc; + if (((cmd >> 8) & 0xff) == 'M') { if (_IOC_DIR (cmd) & _IOC_WRITE) switch (cmd & 0xff) { case SOUND_MIXER_RECSRC: - return snd_ioctl_return ((int *) arg, set_recmask (get_fs_long ((long *) arg))); + return snd_ioctl_return ((int *) arg, set_recmask (devc, get_user ((int *) arg))); break; default: - return snd_ioctl_return ((int *) arg, sb_mixer_set (cmd & 0xff, get_fs_long ((long *) arg))); + return snd_ioctl_return ((int *) arg, sb_mixer_set (devc, cmd & 0xff, get_user ((int *) arg))); } else - switch (cmd & 0xff) /* - * Return parameters - */ + switch (cmd & 0xff) { case SOUND_MIXER_RECSRC: - return snd_ioctl_return ((int *) arg, recmask); + return snd_ioctl_return ((int *) arg, devc->recmask); break; case SOUND_MIXER_DEVMASK: - return snd_ioctl_return ((int *) arg, supported_devices); + return snd_ioctl_return ((int *) arg, devc->supported_devices); break; case SOUND_MIXER_STEREODEVS: - if (Jazz16_detected) - return snd_ioctl_return ((int *) arg, supported_devices); + if (devc->model == MDL_JAZZ || devc->model == MDL_SMW) + return snd_ioctl_return ((int *) arg, devc->supported_devices); else - return snd_ioctl_return ((int *) arg, supported_devices & ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER)); + return snd_ioctl_return ((int *) arg, devc->supported_devices & ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER)); break; case SOUND_MIXER_RECMASK: - return snd_ioctl_return ((int *) arg, supported_rec_devices); + return snd_ioctl_return ((int *) arg, devc->supported_rec_devices); break; case SOUND_MIXER_CAPS: - return snd_ioctl_return ((int *) arg, mixer_caps); + return snd_ioctl_return ((int *) arg, devc->mixer_caps); break; default: - return snd_ioctl_return ((int *) arg, sb_mixer_get (cmd & 0xff)); + return snd_ioctl_return ((int *) arg, sb_mixer_get (devc, cmd & 0xff)); } } else - return -EINVAL; + return -(EINVAL); } static struct mixer_operations sb_mixer_operations = { - "SoundBlaster", + "SB", + "Sound Blaster", sb_mixer_ioctl }; void -sb_mixer_reset (void) +sb_mixer_reset (sb_devc * devc) { int i; for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) - sb_mixer_set (i, levels[i]); - set_recmask (SOUND_MASK_MIC); + sb_mixer_set (devc, i, devc->levels[i]); + set_recmask (devc, SOUND_MASK_MIC); } -/* - * Returns a code depending on whether a SG NX Pro was detected. - * 1 == Plain SB Pro - * 2 == SG NX Pro detected. - * 3 == SB16 - * - * Used to update message. - */ int -sb_mixer_init (int major_model) +sb_mixer_init (sb_devc * devc) { int mixer_type = 0; - sb_setmixer (0x00, 0); /* Reset mixer */ + sb_setmixer (devc, 0x00, 0); /* Reset mixer */ - if (!(mixer_type = detect_mixer ())) + if (!(mixer_type = detect_mixer (devc))) return 0; /* No mixer. Why? */ - mixer_initialized = 1; - mixer_model = major_model; - - switch (major_model) + switch (devc->model) { - case 3: - mixer_caps = SOUND_CAP_EXCL_INPUT; + case MDL_SBPRO: + case MDL_JAZZ: + devc->mixer_caps = SOUND_CAP_EXCL_INPUT; + devc->supported_devices = SBPRO_MIXER_DEVICES; + devc->supported_rec_devices = SBPRO_RECORDING_DEVICES; + devc->iomap = &sbpro_mix; + break; - if (AudioDrive) - { - supported_devices = ES688_MIXER_DEVICES; - supported_rec_devices = ES688_RECORDING_DEVICES; - iomap = &es688_mix; - } - else if (Jazz16_detected == 2) /* SM Wave */ - { - supported_devices = 0; - supported_rec_devices = 0; - iomap = &sbpro_mix; - smw_mixer_init (); - mixer_type = 1; - } - else -#ifdef __SGNXPRO__ - if (mixer_type == 2) /* A SGNXPRO was detected */ - { - supported_devices = SGNXPRO_MIXER_DEVICES; - supported_rec_devices = SGNXPRO_RECORDING_DEVICES; - iomap = &sgnxpro_mix; - } - else -#endif - { - supported_devices = SBPRO_MIXER_DEVICES; - supported_rec_devices = SBPRO_RECORDING_DEVICES; - iomap = &sbpro_mix; - mixer_type = 1; - } + case MDL_ESS: + devc->mixer_caps = SOUND_CAP_EXCL_INPUT; + devc->supported_devices = ES688_MIXER_DEVICES; + devc->supported_rec_devices = ES688_RECORDING_DEVICES; + devc->iomap = &es688_mix; break; - case 4: - mixer_caps = 0; - supported_devices = SB16_MIXER_DEVICES; - supported_rec_devices = SB16_RECORDING_DEVICES; - iomap = &sb16_mix; - mixer_type = 3; + case MDL_SMW: + devc->mixer_caps = SOUND_CAP_EXCL_INPUT; + devc->supported_devices = 0; + devc->supported_rec_devices = 0; + devc->iomap = &sbpro_mix; + smw_mixer_init (devc); + break; + + case MDL_SB16: + devc->mixer_caps = 0; + devc->supported_devices = SB16_MIXER_DEVICES; + devc->supported_rec_devices = SB16_RECORDING_DEVICES; + devc->iomap = &sb16_mix; break; default: - printk ("SB Warning: Unsupported mixer type\n"); + printk ("SB Warning: Unsupported mixer type %d\n", devc->model); return 0; } - if (num_mixers < MAX_MIXER_DEV) - mixer_devs[num_mixers++] = &sb_mixer_operations; - sb_mixer_reset (); - return mixer_type; + if (num_mixers >= MAX_MIXER_DEV) + return 0; + + + mixer_devs[num_mixers] = (struct mixer_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct mixer_operations))); + + if (sound_nblocks < 1024) + sound_nblocks++;; + if (mixer_devs[num_mixers] == NULL) + { + printk ("sb_mixer: Can't allocate memory\n"); + return 0; + } + + memcpy ((char *) mixer_devs[num_mixers], (char *) &sb_mixer_operations, + sizeof (struct mixer_operations)); + + mixer_devs[num_mixers]->devc = devc; + memcpy ((char *) devc->levels, (char *) &default_levels, sizeof (default_levels)); + + sb_mixer_reset (devc); + devc->my_mixerdev = num_mixers++; + return 1; } #endif diff -ur --new-file old/linux/drivers/sound/sb_mixer.h new/linux/drivers/sound/sb_mixer.h --- old/linux/drivers/sound/sb_mixer.h Sun Mar 24 21:49:43 1996 +++ new/linux/drivers/sound/sb_mixer.h Sun Jun 30 10:43:39 1996 @@ -4,27 +4,11 @@ * Definitions for the SB Pro and SB16 mixers */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ /* @@ -109,16 +93,6 @@ #define LEFT_CHN 0 #define RIGHT_CHN 1 -struct mixer_def { - unsigned int regno: 8; - unsigned int bitoffs:4; - unsigned int nbits:4; -}; - - -typedef struct mixer_def mixer_tab[32][2]; -typedef struct mixer_def mixer_ent; - #define MIX_ENT(name, reg_l, bit_l, len_l, reg_r, bit_r, len_r) \ {{reg_l, bit_l, len_l}, {reg_r, bit_r, len_r}} @@ -197,7 +171,7 @@ higher than with SB Pro. This improves the sound quality */ -static unsigned short levels[SOUND_MIXER_NRDEVICES] = +static unsigned short default_levels[SOUND_MIXER_NRDEVICES] = { 0x2020, /* Master Volume */ 0x4b4b, /* Bass */ @@ -220,7 +194,7 @@ #else /* If the user selected just plain SB Pro */ -static unsigned short levels[SOUND_MIXER_NRDEVICES] = +static unsigned short default_levels[SOUND_MIXER_NRDEVICES] = { 0x5a5a, /* Master Volume */ 0x4b4b, /* Bass */ @@ -278,12 +252,33 @@ 0x00 /* SOUND_MIXER_OGAIN */ }; +static char smw_mix_regs[] = /* Left mixer registers */ +{ + 0x0b, /* SOUND_MIXER_VOLUME */ + 0x0d, /* SOUND_MIXER_BASS */ + 0x0d, /* SOUND_MIXER_TREBLE */ + 0x05, /* SOUND_MIXER_SYNTH */ + 0x09, /* SOUND_MIXER_PCM */ + 0x00, /* SOUND_MIXER_SPEAKER */ + 0x03, /* SOUND_MIXER_LINE */ + 0x01, /* SOUND_MIXER_MIC */ + 0x07, /* SOUND_MIXER_CD */ + 0x00, /* SOUND_MIXER_IMIX */ + 0x00, /* SOUND_MIXER_ALTPCM */ + 0x00, /* SOUND_MIXER_RECLEV */ + 0x00, /* SOUND_MIXER_IGAIN */ + 0x00, /* SOUND_MIXER_OGAIN */ + 0x00, /* SOUND_MIXER_LINE1 */ + 0x00, /* SOUND_MIXER_LINE2 */ + 0x00 /* SOUND_MIXER_LINE3 */ +}; + /* * Recording sources (SB Pro) */ -#define SRC_MIC 1 /* Select Microphone recording source */ -#define SRC_CD 3 /* Select CD recording source */ -#define SRC_LINE 7 /* Use Line-in for recording source */ +#define SRC__MIC 1 /* Select Microphone recording source */ +#define SRC__CD 3 /* Select CD recording source */ +#define SRC__LINE 7 /* Use Line-in for recording source */ #endif diff -ur --new-file old/linux/drivers/sound/sequencer.c new/linux/drivers/sound/sequencer.c --- old/linux/drivers/sound/sequencer.c Mon Jun 3 11:33:14 1996 +++ new/linux/drivers/sound/sequencer.c Sun Aug 18 09:46:49 1996 @@ -4,27 +4,11 @@ * The sequencer personality manager. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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 @@ -85,7 +69,7 @@ static volatile int iqhead = 0, iqtail = 0, iqlen = 0; static volatile int seq_playing = 0; static volatile int sequencer_busy = 0; -static int output_treshold; +static int output_threshold; static int pre_event_timeout; static unsigned synth_open_mask; @@ -124,25 +108,25 @@ 1 : 0)) { restore_flags (flags); - return -EAGAIN; + return -(EAGAIN); } { - unsigned long tl; + unsigned long tlimit; if (pre_event_timeout) - current_set_timeout (tl = jiffies + (pre_event_timeout)); + current_set_timeout (tlimit = jiffies + (pre_event_timeout)); else - tl = (unsigned long) -1; - midi_sleep_flag.mode = WK_SLEEP; + tlimit = (unsigned long) -1; + midi_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&midi_sleeper); - if (!(midi_sleep_flag.mode & WK_WAKEUP)) + if (!(midi_sleep_flag.flags & WK_WAKEUP)) { - if (jiffies >= tl) - midi_sleep_flag.mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + midi_sleep_flag.flags |= WK_TIMEOUT; } - midi_sleep_flag.mode &= ~WK_SLEEP; + midi_sleep_flag.flags &= ~WK_SLEEP; }; if (!iqlen) @@ -155,7 +139,7 @@ while (iqlen && c >= ev_len) { - memcpy_tofs (&((buf)[p]), (char *) &iqueue[iqhead * IEV_SZ], ev_len); + memcpy_tofs (&(buf)[p], (char *) &iqueue[iqhead * IEV_SZ], ev_len); p += ev_len; c -= ev_len; @@ -198,10 +182,10 @@ iqlen++; iqtail = (iqtail + 1) % SEQ_MAX_QUEUE; - if ((midi_sleep_flag.mode & WK_SLEEP)) + if ((midi_sleep_flag.flags & WK_SLEEP)) { { - midi_sleep_flag.mode = WK_WAKEUP; + midi_sleep_flag.flags = WK_WAKEUP; module_wake_up (&midi_sleeper); }; } @@ -274,7 +258,7 @@ DEB (printk ("sequencer_write(dev=%d, count=%d)\n", dev, count)); if (mode == OPEN_READ) - return -EIO; + return -(EIO); if (dev) return pmgr_write (dev - 1, file, buf, count); @@ -283,7 +267,7 @@ while (c >= 4) { - memcpy_fromfs ((char *) event_rec, &((buf)[p]), 4); + memcpy_fromfs ((char *) event_rec, &(buf)[p], 4); ev_code = event_rec[0]; if (ev_code == SEQ_FULLSIZE) @@ -292,10 +276,10 @@ dev = *(unsigned short *) &event_rec[2]; if (dev < 0 || dev >= max_synthdev) - return -ENXIO; + return -(ENXIO); if (!(synth_open_mask & (1 << dev))) - return -ENXIO; + return -(ENXIO); err = synth_devs[dev]->load_patch (dev, *(short *) &event_rec[0], buf, p + 4, c, 0); if (err < 0) @@ -309,7 +293,7 @@ if (seq_mode == SEQ_2 && ev_code == SEQ_EXTENDED) { printk ("Sequencer: Invalid level 2 event %x\n", ev_code); - return -EINVAL; + return -(EINVAL); } ev_size = 8; @@ -321,7 +305,7 @@ return count - c; } - memcpy_fromfs ((char *) &event_rec[4], &((buf)[p + 4]), 4); + memcpy_fromfs ((char *) &event_rec[4], &(buf)[p + 4], 4); } else @@ -329,7 +313,7 @@ if (seq_mode == SEQ_2) { printk ("Sequencer: 4 byte event in level 2 mode\n"); - return -EINVAL; + return -(EINVAL); } ev_size = 4; } @@ -345,7 +329,7 @@ if (dev >= max_mididev) { printk ("Sequencer Error: Nonexistent MIDI device %d\n", dev); - return -ENXIO; + return -(ENXIO); } mode = file->mode & O_ACCMODE; @@ -373,7 +357,7 @@ if (!processed && (file->flags & (O_NONBLOCK) ? 1 : 0)) - return -EAGAIN; + return -(EAGAIN); else return processed; } @@ -404,15 +388,15 @@ * Give chance to drain the queue */ - if (!nonblock && qlen >= SEQ_MAX_QUEUE && !(seq_sleep_flag.mode & WK_SLEEP)) + if (!nonblock && qlen >= SEQ_MAX_QUEUE && !(seq_sleep_flag.flags & WK_SLEEP)) { /* * Sleep until there is enough space on the queue */ - seq_sleep_flag.mode = WK_SLEEP; + seq_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&seq_sleeper); - seq_sleep_flag.mode &= ~WK_SLEEP;; + seq_sleep_flag.flags &= ~WK_SLEEP;; } if (qlen >= SEQ_MAX_QUEUE) @@ -435,10 +419,10 @@ int dev = q[2]; if (dev < 0 || dev >= max_synthdev) - return -ENXIO; + return -(ENXIO); if (!(synth_open_mask & (1 << dev))) - return -ENXIO; + return -(ENXIO); switch (q[1]) { @@ -475,7 +459,7 @@ break; default: - return -EINVAL; + return -(EINVAL); } return 0; @@ -565,6 +549,7 @@ if (chn == 9) { synth_devs[dev]->set_instr (dev, voice, 128 + note); + synth_devs[dev]->chn_info[chn].pgm_num = 128 + note; note = 60; /* Middle C */ } @@ -704,16 +689,16 @@ if ((ret = tmr->event (tmr_no, event_rec)) == TIMER_ARMED) { - if ((SEQ_MAX_QUEUE - qlen) >= output_treshold) + if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) { unsigned long flags; save_flags (flags); cli (); - if ((seq_sleep_flag.mode & WK_SLEEP)) + if ((seq_sleep_flag.flags & WK_SLEEP)) { { - seq_sleep_flag.mode = WK_WAKEUP; + seq_sleep_flag.flags = WK_WAKEUP; module_wake_up (&seq_sleeper); }; } @@ -744,16 +729,16 @@ request_sound_timer (time); - if ((SEQ_MAX_QUEUE - qlen) >= output_treshold) + if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) { unsigned long flags; save_flags (flags); cli (); - if ((seq_sleep_flag.mode & WK_SLEEP)) + if ((seq_sleep_flag.flags & WK_SLEEP)) { { - seq_sleep_flag.mode = WK_WAKEUP; + seq_sleep_flag.flags = WK_WAKEUP; module_wake_up (&seq_sleeper); }; } @@ -880,16 +865,16 @@ request_sound_timer (time); - if ((SEQ_MAX_QUEUE - qlen) >= output_treshold) + if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) { unsigned long flags; save_flags (flags); cli (); - if ((seq_sleep_flag.mode & WK_SLEEP)) + if ((seq_sleep_flag.flags & WK_SLEEP)) { { - seq_sleep_flag.mode = WK_WAKEUP; + seq_sleep_flag.flags = WK_WAKEUP; module_wake_up (&seq_sleeper); }; } @@ -927,7 +912,7 @@ dev = q[2]; if (dev < 0 || dev >= num_midis) - break; + break; if (!midi_devs[dev]->putc (dev, q[1])) { @@ -946,7 +931,7 @@ case SEQ_ECHO: seq_copy_to_input (q, 4); /* - * Echo back to the process + * Echo back to the process */ break; @@ -1019,16 +1004,16 @@ seq_playing = 0; - if ((SEQ_MAX_QUEUE - qlen) >= output_treshold) + if ((SEQ_MAX_QUEUE - qlen) >= output_threshold) { unsigned long flags; save_flags (flags); cli (); - if ((seq_sleep_flag.mode & WK_SLEEP)) + if ((seq_sleep_flag.flags & WK_SLEEP)) { { - seq_sleep_flag.mode = WK_WAKEUP; + seq_sleep_flag.flags = WK_WAKEUP; module_wake_up (&seq_sleeper); }; } @@ -1095,13 +1080,13 @@ if (!sequencer_ok) { printk ("Soundcard: Sequencer not initialized\n"); - return -ENXIO; + return -(ENXIO); } if (dev) /* Patch manager device */ { printk ("Patch manager interface is currently broken. Sorry\n"); - return -ENXIO; + return -(ENXIO); } save_flags (flags); @@ -1110,7 +1095,7 @@ { printk ("Sequencer busy\n"); restore_flags (flags); - return -EBUSY; + return -(EBUSY); } sequencer_busy = 1; restore_flags (flags); @@ -1150,7 +1135,7 @@ { printk ("sequencer: No timer for level 2\n"); sequencer_busy = 0; - return -ENXIO; + return -(ENXIO); } setup_mode2 (); } @@ -1160,11 +1145,11 @@ { printk ("Sequencer: No Midi devices. Input not possible\n"); sequencer_busy = 0; - return -ENXIO; + return -(ENXIO); } if (!max_synthdev && !max_mididev) - return -ENXIO; + return -(ENXIO); synth_open_mask = 0; @@ -1217,9 +1202,9 @@ tmr->open (tmr_no, seq_mode); } - seq_sleep_flag.mode = WK_NONE; - midi_sleep_flag.mode = WK_NONE; - output_treshold = SEQ_MAX_QUEUE / 2; + seq_sleep_flag.flags = WK_NONE; + midi_sleep_flag.flags = WK_NONE; + output_threshold = SEQ_MAX_QUEUE / 2; for (i = 0; i < num_synths; i++) if (pmgr_present[i]) @@ -1256,20 +1241,20 @@ { { - unsigned long tl; + unsigned long tlimit; if (HZ / 10) - current_set_timeout (tl = jiffies + (HZ / 10)); + current_set_timeout (tlimit = jiffies + (HZ / 10)); else - tl = (unsigned long) -1; - seq_sleep_flag.mode = WK_SLEEP; + tlimit = (unsigned long) -1; + seq_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&seq_sleeper); - if (!(seq_sleep_flag.mode & WK_WAKEUP)) + if (!(seq_sleep_flag.flags & WK_WAKEUP)) { - if (jiffies >= tl) - seq_sleep_flag.mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + seq_sleep_flag.flags |= WK_TIMEOUT; } - seq_sleep_flag.mode &= ~WK_SLEEP; + seq_sleep_flag.flags &= ~WK_SLEEP; }; } } @@ -1352,24 +1337,24 @@ save_flags (flags); cli (); - if (qlen && !(seq_sleep_flag.mode & WK_SLEEP)) + if (qlen && !(seq_sleep_flag.flags & WK_SLEEP)) { { - unsigned long tl; + unsigned long tlimit; if (HZ) - current_set_timeout (tl = jiffies + (HZ)); + current_set_timeout (tlimit = jiffies + (HZ)); else - tl = (unsigned long) -1; - seq_sleep_flag.mode = WK_SLEEP; + tlimit = (unsigned long) -1; + seq_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&seq_sleeper); - if (!(seq_sleep_flag.mode & WK_WAKEUP)) + if (!(seq_sleep_flag.flags & WK_WAKEUP)) { - if (jiffies >= tl) - seq_sleep_flag.mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + seq_sleep_flag.flags |= WK_TIMEOUT; } - seq_sleep_flag.mode &= ~WK_SLEEP; + seq_sleep_flag.flags &= ~WK_SLEEP; }; } restore_flags (flags); @@ -1389,7 +1374,7 @@ /* * This routine sends one byte to the Midi channel. - * If the output Fifo is full, it waits until there + * If the output FIFO is full, it waits until there * is space in the queue */ @@ -1401,20 +1386,20 @@ { { - unsigned long tl; + unsigned long tlimit; if (4) - current_set_timeout (tl = jiffies + (4)); + current_set_timeout (tlimit = jiffies + (4)); else - tl = (unsigned long) -1; - seq_sleep_flag.mode = WK_SLEEP; + tlimit = (unsigned long) -1; + seq_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&seq_sleeper); - if (!(seq_sleep_flag.mode & WK_WAKEUP)) + if (!(seq_sleep_flag.flags & WK_WAKEUP)) { - if (jiffies >= tl) - seq_sleep_flag.mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + seq_sleep_flag.flags |= WK_TIMEOUT; } - seq_sleep_flag.mode &= ~WK_SLEEP; + seq_sleep_flag.flags &= ~WK_SLEEP; }; n--; } @@ -1493,11 +1478,11 @@ save_flags (flags); cli (); - if ((seq_sleep_flag.mode & WK_SLEEP)) + if ((seq_sleep_flag.flags & WK_SLEEP)) { /* printk ("Sequencer Warning: Unexpected sleeping process - Waking up\n"); */ { - seq_sleep_flag.mode = WK_WAKEUP; + seq_sleep_flag.flags = WK_WAKEUP; module_wake_up (&seq_sleeper); }; } @@ -1546,25 +1531,25 @@ case SNDCTL_TMR_METRONOME: case SNDCTL_TMR_SOURCE: if (dev) /* Patch manager */ - return -EIO; + return -(EIO); if (seq_mode != SEQ_2) - return -EINVAL; + return -(EINVAL); return tmr->ioctl (tmr_no, cmd, arg); break; case SNDCTL_TMR_SELECT: if (dev) /* Patch manager */ - return -EIO; + return -(EIO); if (seq_mode != SEQ_2) - return -EINVAL; - pending_timer = get_fs_long ((long *) arg); + return -(EINVAL); + pending_timer = get_user ((int *) arg); if (pending_timer < 0 || pending_timer >= num_sound_timers) { pending_timer = -1; - return -EINVAL; + return -(EINVAL); } return snd_ioctl_return ((int *) arg, pending_timer); @@ -1578,14 +1563,14 @@ if (dev) /* * Patch manager */ - return -EIO; + return -(EIO); if (mode == OPEN_READ) return 0; while (qlen && !current_got_fatal_signal ()) seq_sync (); if (qlen) - return -EINTR; + return -(EINTR); else return 0; break; @@ -1594,7 +1579,7 @@ if (dev) /* * Patch manager */ - return -EIO; + return -(EIO); seq_reset (); return 0; @@ -1604,11 +1589,11 @@ if (dev) /* * Patch manager */ - return -EIO; + return -(EIO); - midi_dev = get_fs_long ((long *) arg); + midi_dev = get_user ((int *) arg); if (midi_dev >= max_mididev) - return -ENXIO; + return -(ENXIO); if (!midi_opened[midi_dev]) { @@ -1630,7 +1615,7 @@ if (dev) /* * Patch manager */ - return -EIO; + return -(EIO); if (mode == OPEN_WRITE) return 0; @@ -1646,7 +1631,7 @@ case SNDCTL_SEQ_CTRLRATE: if (dev) /* Patch manager */ - return -EIO; + return -(EIO); /* * If *arg == 0, just return the current rate @@ -1654,8 +1639,8 @@ if (seq_mode == SEQ_2) return tmr->ioctl (tmr_no, cmd, arg); - if (get_fs_long ((long *) arg) != 0) - return -EINVAL; + if (get_user ((int *) arg) != 0) + return -(EINVAL); return snd_ioctl_return ((int *) arg, HZ); break; @@ -1664,15 +1649,15 @@ { int err; - dev = get_fs_long ((long *) arg); + dev = get_user ((int *) arg); if (dev < 0 || dev >= num_synths) { - return -ENXIO; + return -(ENXIO); } if (!(synth_open_mask & (1 << dev)) && !orig_dev) { - return -EBUSY; + return -(EBUSY); } if (!orig_dev && pmgr_present[dev]) @@ -1693,13 +1678,13 @@ case SNDCTL_SYNTH_MEMAVL: { - int dev = get_fs_long ((long *) arg); + int dev = get_user ((int *) arg); if (dev < 0 || dev >= num_synths) - return -ENXIO; + return -(ENXIO); if (!(synth_open_mask & (1 << dev)) && !orig_dev) - return -EBUSY; + return -(EBUSY); return snd_ioctl_return ((int *) arg, synth_devs[dev]->ioctl (dev, cmd, arg)); } @@ -1707,13 +1692,13 @@ case SNDCTL_FM_4OP_ENABLE: { - int dev = get_fs_long ((long *) arg); + int dev = get_user ((int *) arg); if (dev < 0 || dev >= num_synths) - return -ENXIO; + return -(ENXIO); if (!(synth_open_mask & (1 << dev))) - return -ENXIO; + return -(ENXIO); synth_devs[dev]->ioctl (dev, cmd, arg); return 0; @@ -1725,14 +1710,14 @@ struct synth_info inf; int dev; - memcpy_fromfs ((char *) &inf, &(((char *) arg)[0]), sizeof (inf)); + memcpy_fromfs ((char *) &inf, &((char *) arg)[0], sizeof (inf)); dev = inf.device; if (dev < 0 || dev >= max_synthdev) - return -ENXIO; + return -(ENXIO); if (!(synth_open_mask & (1 << dev)) && !orig_dev) - return -EBUSY; + return -(EBUSY); return synth_devs[dev]->ioctl (dev, cmd, arg); } @@ -1743,7 +1728,7 @@ struct seq_event_rec event_rec; unsigned long flags; - memcpy_fromfs ((char *) &event_rec, &(((char *) arg)[0]), sizeof (event_rec)); + memcpy_fromfs ((char *) &event_rec, &((char *) arg)[0], sizeof (event_rec)); save_flags (flags); cli (); @@ -1759,13 +1744,13 @@ struct midi_info inf; int dev; - memcpy_fromfs ((char *) &inf, &(((char *) arg)[0]), sizeof (inf)); + memcpy_fromfs ((char *) &inf, &((char *) arg)[0], sizeof (inf)); dev = inf.device; if (dev < 0 || dev >= max_mididev) - return -ENXIO; + return -(ENXIO); - memcpy_tofs ((&((char *) arg)[0]), (char *) &(midi_devs[dev]->info), sizeof (inf)); + memcpy_tofs (&((char *) arg)[0], (char *) &(midi_devs[dev]->info), sizeof (inf)); return 0; } break; @@ -1775,35 +1760,35 @@ struct patmgr_info *inf; int dev, err; - if ((inf = (struct patmgr_info *) kmalloc (sizeof (*inf), GFP_KERNEL)) == NULL) + if ((inf = (struct patmgr_info *) vmalloc (sizeof (*inf))) == NULL) { printk ("patmgr: Can't allocate memory for a message\n"); - return -EIO; + return -(EIO); } - memcpy_fromfs ((char *) inf, &(((char *) arg)[0]), sizeof (*inf)); + memcpy_fromfs ((char *) inf, &((char *) arg)[0], sizeof (*inf)); dev = inf->device; if (dev < 0 || dev >= num_synths) { - kfree (inf); - return -ENXIO; + vfree (inf); + return -(ENXIO); } if (!synth_devs[dev]->pmgr_interface) { - kfree (inf); - return -ENXIO; + vfree (inf); + return -(ENXIO); } if ((err = synth_devs[dev]->pmgr_interface (dev, inf)) == -1) { - kfree (inf); + vfree (inf); return err; } - memcpy_tofs ((&((char *) arg)[0]), (char *) inf, sizeof (*inf)); - kfree (inf); + memcpy_tofs (&((char *) arg)[0], (char *) inf, sizeof (*inf)); + vfree (inf); return 0; } break; @@ -1813,60 +1798,60 @@ struct patmgr_info *inf; int dev, err; - if ((inf = (struct patmgr_info *) kmalloc (sizeof (*inf), GFP_KERNEL)) == NULL) + if ((inf = (struct patmgr_info *) vmalloc (sizeof (*inf))) == NULL) { printk ("patmgr: Can't allocate memory for a message\n"); - return -EIO; + return -(EIO); } - memcpy_fromfs ((char *) inf, &(((char *) arg)[0]), sizeof (*inf)); + memcpy_fromfs ((char *) inf, &((char *) arg)[0], sizeof (*inf)); dev = inf->device; if (dev < 0 || dev >= num_synths) { - kfree (inf); - return -ENXIO; + vfree (inf); + return -(ENXIO); } if (!pmgr_present[dev]) { - kfree (inf); - return -ESRCH; + vfree (inf); + return -(ESRCH); } if ((err = pmgr_access (dev, inf)) < 0) { - kfree (inf); + vfree (inf); return err; } - memcpy_tofs ((&((char *) arg)[0]), (char *) inf, sizeof (*inf)); - kfree (inf); + memcpy_tofs (&((char *) arg)[0], (char *) inf, sizeof (*inf)); + vfree (inf); return 0; } break; case SNDCTL_SEQ_THRESHOLD: { - int tmp = get_fs_long ((long *) arg); + int tmp = get_user ((int *) arg); if (dev) /* * Patch manager */ - return -EIO; + return -(EIO); if (tmp < 1) tmp = 1; if (tmp >= SEQ_MAX_QUEUE) tmp = SEQ_MAX_QUEUE - 1; - output_treshold = tmp; + output_threshold = tmp; return 0; } break; case SNDCTL_MIDI_PRETIME: { - int val = get_fs_long ((long *) arg); + int val = get_user ((int *) arg); if (val < 0) val = 0; @@ -1881,20 +1866,20 @@ if (dev) /* * Patch manager */ - return -EIO; + return -(EIO); if (mode == OPEN_READ) - return -EIO; + return -(EIO); if (!synth_devs[0]) - return -ENXIO; + return -(ENXIO); if (!(synth_open_mask & (1 << 0))) - return -ENXIO; + return -(ENXIO); return synth_devs[0]->ioctl (0, cmd, arg); break; } - return -EINVAL; + return -(EINVAL); } int @@ -1912,7 +1897,7 @@ if (!iqlen) { - midi_sleep_flag.mode = WK_SLEEP; + midi_sleep_flag.flags = WK_SLEEP; module_select_wait (&midi_sleeper, wait); restore_flags (flags); return 0; @@ -1924,10 +1909,10 @@ case SEL_OUT: save_flags (flags); cli (); - if ((SEQ_MAX_QUEUE - qlen) < output_treshold) + if ((SEQ_MAX_QUEUE - qlen) < output_threshold) { - seq_sleep_flag.mode = WK_SLEEP; + seq_sleep_flag.flags = WK_SLEEP; module_select_wait (&seq_sleeper, wait); restore_flags (flags); return 0; @@ -2035,33 +2020,31 @@ } -long -sequencer_init (long mem_start) +void +sequencer_init (void) { - queue = (unsigned char *) (sound_mem_blocks[sound_num_blocks] = kmalloc (SEQ_MAX_QUEUE * EV_SZ, GFP_KERNEL)); - if (sound_num_blocks < 1024) - sound_num_blocks++;; + queue = (unsigned char *) (sound_mem_blocks[sound_nblocks] = vmalloc (SEQ_MAX_QUEUE * EV_SZ)); + if (sound_nblocks < 1024) + sound_nblocks++;; if (queue == NULL) { printk ("Sound: Can't allocate memory for sequencer output queue\n"); - return mem_start; + return; } - iqueue = (unsigned char *) (sound_mem_blocks[sound_num_blocks] = kmalloc (SEQ_MAX_QUEUE * IEV_SZ, GFP_KERNEL)); - if (sound_num_blocks < 1024) - sound_num_blocks++;; + iqueue = (unsigned char *) (sound_mem_blocks[sound_nblocks] = vmalloc (SEQ_MAX_QUEUE * IEV_SZ)); + if (sound_nblocks < 1024) + sound_nblocks++;; if (queue == NULL) { printk ("Sound: Can't allocate memory for sequencer input queue\n"); - return mem_start; + return; } sequencer_ok = 1; - - return mem_start; } #endif diff -ur --new-file old/linux/drivers/sound/sound_calls.h new/linux/drivers/sound/sound_calls.h --- old/linux/drivers/sound/sound_calls.h Sun Mar 24 21:49:43 1996 +++ new/linux/drivers/sound/sound_calls.h Sun Jun 30 10:43:39 1996 @@ -11,7 +11,7 @@ int DMAbuf_start_output(int dev, int buff_no, int l); int DMAbuf_set_count(int dev, int buff_no, int l); int DMAbuf_ioctl(int dev, unsigned int cmd, caddr_t arg, int local); -long DMAbuf_init(long mem_start); +void DMAbuf_init(void); int DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode); int DMAbuf_open_dma (int dev); void DMAbuf_close_dma (int dev); @@ -32,7 +32,7 @@ int audio_ioctl (int dev, struct fileinfo *file, unsigned int cmd, caddr_t arg); int audio_lseek (int dev, struct fileinfo *file, off_t offset, int orig); -long audio_init (long mem_start); +void audio_init (void); int audio_select(int dev, struct fileinfo *file, int sel_type, select_table_handle * wait); @@ -47,7 +47,7 @@ int sequencer_ioctl (int dev, struct fileinfo *file, unsigned int cmd, caddr_t arg); int sequencer_lseek (int dev, struct fileinfo *file, off_t offset, int orig); -long sequencer_init (long mem_start); +void sequencer_init (void); void sequencer_timer(unsigned long dummy); int note_to_freq(int note_num); unsigned long compute_finetune(unsigned long base_freq, int bend, int range); @@ -68,7 +68,7 @@ unsigned int cmd, caddr_t arg); int MIDIbuf_lseek (int dev, struct fileinfo *file, off_t offset, int orig); void MIDIbuf_bytes_received(int dev, unsigned char *buf, int count); -long MIDIbuf_init(long mem_start); +void MIDIbuf_init(void); int MIDIbuf_select(int dev, struct fileinfo *file, int sel_type, select_table_handle * wait); @@ -83,7 +83,7 @@ void request_sound_timer (int count); void sound_stop_timer(void); int snd_ioctl_return(int *addr, int value); -int snd_set_irq_handler (int interrupt_level, void(*hndlr)(int, void*, struct pt_regs *), char *name, int *osp); +int snd_set_irq_handler (int interrupt_level, void(*iproc)(int, void*, struct pt_regs *), char *name, int *osp); void snd_release_irq(int vect); void sound_dma_malloc(int dev); void sound_dma_free(int dev); @@ -98,51 +98,33 @@ int sound_ioctl_sw (int dev, struct fileinfo *file, unsigned int cmd, caddr_t arg); -/* From sb_dsp.c */ -int sb_dsp_detect (struct address_info *hw_config); -long sb_dsp_init (long mem_start, struct address_info *hw_config); -void sb_dsp_disable_midi(void); -int sb_get_irq(void); -void sb_free_irq(void); -int sb_dsp_command (unsigned char val); -int sb_reset_dsp (void); -void sb_dsp_unload(struct address_info *); - -/* From sb16_dsp.c */ -void sb16_dsp_interrupt (int irq); -long sb16_dsp_init(long mem_start, struct address_info *hw_config); -int sb16_dsp_detect(struct address_info *hw_config); - -/* From sb16_midi.c */ -void sb16midiintr (int unit); -long attach_sb16midi(long mem_start, struct address_info * hw_config); -int probe_sb16midi(struct address_info *hw_config); -void sb_midi_interrupt(int dummy); -void sbmidiintr(int irq, void *dev_id, struct pt_regs * dummy); - -/* From sb_midi.c */ -void sb_midi_init(int model); - -/* From sb_mixer.c */ -void sb_setmixer (unsigned int port, unsigned int value); -int sb_getmixer (unsigned int port); -void sb_mixer_set_stereo(int mode); -int sb_mixer_init(int major_model); - /* From opl3.c */ int opl3_detect (int ioaddr, int *osp); -long opl3_init(long mem_start, int ioaddr, int *osp); +void opl3_init(int ioaddr, int *osp); /* From sb_card.c */ -long attach_sb_card(long mem_start, struct address_info *hw_config); +void attach_sb_card(struct address_info *hw_config); int probe_sb(struct address_info *hw_config); +/* From sb_common.c */ +void sb_dsp_disable_midi(int port); +void sb_dsp_disable_recording(int port); +void attach_sbmpu (struct address_info *hw_config); +int probe_sbmpu (struct address_info *hw_config); +void unload_sbmpu (struct address_info *hw_config); + +/* From uart401.c */ +void attach_uart401 (struct address_info *hw_config); +int probe_uart401 (struct address_info *hw_config); +void unload_uart401 (struct address_info *hw_config); +void uart401intr (int irq, void *dev_id, struct pt_regs * dummy); + /* From adlib_card.c */ -long attach_adlib_card(long mem_start, struct address_info *hw_config); +void attach_adlib_card(struct address_info *hw_config); int probe_adlib(struct address_info *hw_config); /* From pas_card.c */ -long attach_pas_card(long mem_start, struct address_info *hw_config); +void attach_pas_card(struct address_info *hw_config); int probe_pas(struct address_info *hw_config); int pas_set_intr(int mask); int pas_remove_intr(int mask); @@ -151,26 +133,26 @@ /* From pas_audio.c */ void pas_pcm_interrupt(unsigned char status, int cause); -long pas_pcm_init(long mem_start, struct address_info *hw_config); +void pas_pcm_init(struct address_info *hw_config); /* From pas_mixer.c */ int pas_init_mixer(void); /* From pas_midi.c */ -long pas_midi_init(long mem_start); +void pas_midi_init(void); void pas_midi_interrupt(void); /* From gus_card.c */ -long attach_gus_card(long mem_start, struct address_info * hw_config); +void attach_gus_card(struct address_info * hw_config); int probe_gus(struct address_info *hw_config); int gus_set_midi_irq(int num); void gusintr(int irq, void *dev_id, struct pt_regs * dummy); -long attach_gus_db16(long mem_start, struct address_info * hw_config); +void attach_gus_db16(struct address_info * hw_config); int probe_gus_db16(struct address_info *hw_config); /* From gus_wave.c */ int gus_wave_detect(int baseaddr); -long gus_wave_init(long mem_start, struct address_info *hw_config); +void gus_wave_init(struct address_info *hw_config); void gus_wave_unload (void); void gus_voice_irq(void); unsigned char gus_read8 (int reg); @@ -181,16 +163,16 @@ void gus_timer_command (unsigned int addr, unsigned int val); /* From gus_midi.c */ -long gus_midi_init(long mem_start); +void gus_midi_init(void); void gus_midi_interrupt(int dummy); /* From mpu401.c */ -long attach_mpu401(long mem_start, struct address_info * hw_config); +void attach_mpu401(struct address_info * hw_config); int probe_mpu401(struct address_info *hw_config); void mpuintr(int irq, void *dev_id, struct pt_regs * dummy); /* From uart6850.c */ -long attach_uart6850(long mem_start, struct address_info * hw_config); +void attach_uart6850(struct address_info * hw_config); int probe_uart6850(struct address_info *hw_config); /* From opl3.c */ @@ -206,7 +188,7 @@ unsigned long parm3, unsigned long parm4); /* From ics2101.c */ -long ics2101_mixer_init(long mem_start); +void ics2101_mixer_init(void); /* From sound_timer.c */ void sound_timer_interrupt(void); @@ -221,25 +203,25 @@ #define AD_F_CS4248 0x0001 /* Returned if a CS4248 (or compatible) detected */ void ad1848_interrupt (int irq, void *dev_id, struct pt_regs * dummy); -long attach_ms_sound(long mem_start, struct address_info * hw_config); +void attach_ms_sound(struct address_info * hw_config); int probe_ms_sound(struct address_info *hw_config); -long attach_pnp_ad1848(long mem_start, struct address_info * hw_config); +void attach_pnp_ad1848(struct address_info * hw_config); int probe_pnp_ad1848(struct address_info *hw_config); void unload_pnp_ad1848(struct address_info *hw_info); /* From pss.c */ int probe_pss (struct address_info *hw_config); -long attach_pss (long mem_start, struct address_info *hw_config); +void attach_pss (struct address_info *hw_config); int probe_pss_mpu (struct address_info *hw_config); -long attach_pss_mpu (long mem_start, struct address_info *hw_config); +void attach_pss_mpu (struct address_info *hw_config); int probe_pss_mss (struct address_info *hw_config); -long attach_pss_mss (long mem_start, struct address_info *hw_config); +void attach_pss_mss (struct address_info *hw_config); /* From sscape.c */ int probe_sscape (struct address_info *hw_config); -long attach_sscape (long mem_start, struct address_info *hw_config); +void attach_sscape (struct address_info *hw_config); int probe_ss_ms_sound (struct address_info *hw_config); -long attach_ss_ms_sound(long mem_start, struct address_info * hw_config); +void attach_ss_ms_sound(struct address_info * hw_config); int pss_read (int dev, struct fileinfo *file, char *buf, int count); int pss_write (int dev, struct fileinfo *file, char *buf, int count); @@ -248,7 +230,7 @@ int pss_ioctl (int dev, struct fileinfo *file, unsigned int cmd, caddr_t arg); int pss_lseek (int dev, struct fileinfo *file, off_t offset, int orig); -long pss_init(long mem_start); +void pss_init(void); /* From aedsp16.c */ int InitAEDSP16_SBPRO(struct address_info *hw_config); @@ -259,21 +241,19 @@ void do_midi_msg (int synthno, unsigned char *msg, int mlen); /* From trix.c */ -long attach_trix_wss (long mem_start, struct address_info *hw_config); +void attach_trix_wss (struct address_info *hw_config); int probe_trix_wss (struct address_info *hw_config); -long attach_trix_sb (long mem_start, struct address_info *hw_config); +void attach_trix_sb (struct address_info *hw_config); int probe_trix_sb (struct address_info *hw_config); -long attach_trix_mpu (long mem_start, struct address_info *hw_config); +void attach_trix_mpu (struct address_info *hw_config); int probe_trix_mpu (struct address_info *hw_config); /* From mad16.c */ -long attach_mad16 (long mem_start, struct address_info *hw_config); +void attach_mad16 (struct address_info *hw_config); int probe_mad16 (struct address_info *hw_config); -long attach_mad16_mpu (long mem_start, struct address_info *hw_config); +void attach_mad16_mpu (struct address_info *hw_config); int probe_mad16_mpu (struct address_info *hw_config); int mad16_sb_dsp_detect (struct address_info *hw_config); -long mad16_sb_dsp_init (long mem_start, struct address_info *hw_config); -void mad16_sb_dsp_unload(struct address_info *hw_config); /* Unload routines from various source files*/ void unload_pss(struct address_info *hw_info); @@ -303,14 +283,14 @@ /* From cs4232.c */ int probe_cs4232 (struct address_info *hw_config); -long attach_cs4232 (long mem_start, struct address_info *hw_config); +void attach_cs4232 (struct address_info *hw_config); int probe_cs4232_mpu (struct address_info *hw_config); -long attach_cs4232_mpu (long mem_start, struct address_info *hw_config); +void attach_cs4232_mpu (struct address_info *hw_config); /* From maui.c */ -long attach_maui(long mem_start, struct address_info * hw_config); +void attach_maui(struct address_info * hw_config); int probe_maui(struct address_info *hw_config); /* From sound_pnp.c */ -void sound_pnp_init(void); +void sound_pnp_init(int *osp); void sound_pnp_disconnect(void); diff -ur --new-file old/linux/drivers/sound/sound_config.h new/linux/drivers/sound/sound_config.h --- old/linux/drivers/sound/sound_config.h Fri Apr 12 08:49:43 1996 +++ new/linux/drivers/sound/sound_config.h Tue Aug 20 16:36:20 1996 @@ -3,27 +3,11 @@ * A driver for Soundcards, misc configuration parameters. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ @@ -50,7 +34,7 @@ /************* PCM DMA buffer sizes *******************/ -/* If you are using high playback or recording speeds, the default buffersize +/* If you are using high playback or recording speeds, the default buffer size is too small. DSP_BUFFSIZE must be 64k or less. A rule of thumb is 64k for PAS16, 32k for PAS+, 16k for SB Pro and @@ -112,7 +96,7 @@ #define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */ #define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */ #define SND_DEV_STATUS 6 /* /dev/sndstat */ -/* #7 not in use now. Was in 2.4. Free for use after v3.0. */ +#define SND_DEV_AWFM 7 /* Reserved */ #define SND_DEV_SEQ2 8 /* /dev/sequencer, level 2 interface */ #define SND_DEV_SNDPROC 9 /* /dev/sndproc for programmable devices */ #define SND_DEV_PSS SND_DEV_SNDPROC diff -ur --new-file old/linux/drivers/sound/sound_switch.c new/linux/drivers/sound/sound_switch.c --- old/linux/drivers/sound/sound_switch.c Mon May 6 06:28:52 1996 +++ new/linux/drivers/sound/sound_switch.c Sun Jun 30 10:44:18 1996 @@ -4,27 +4,11 @@ * The system call switch handler */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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 @@ -48,7 +32,7 @@ static int put_status (char *s) { - int l = strnlen (s, 256); + int l = strlen (s); if (status_len + l >= 4000) return 0; @@ -172,18 +156,24 @@ if (!put_status (sound_drivers[drv].name)) return; - if (!put_status (" at 0x")) - return; - if (!put_status_int (snd_installed_cards[i].config.io_base, 16)) - return; + if (snd_installed_cards[i].config.io_base) + { + if (!put_status (" at 0x")) + return; + if (!put_status_int (snd_installed_cards[i].config.io_base, 16)) + return; + } - if (!put_status (" irq ")) - return; tmp = snd_installed_cards[i].config.irq; - if (tmp < 0) - tmp = -tmp; - if (!put_status_int (tmp, 10)) - return; + if (tmp != 0) + { + if (!put_status (" irq ")) + return; + if (tmp < 0) + tmp = -tmp; + if (!put_status_int (tmp, 10)) + return; + } if (snd_installed_cards[i].config.dma != -1) { @@ -326,7 +316,7 @@ if (l <= 0) return 0; - memcpy_tofs (&((buf)[0]), &status_buf[status_ptr], l); + memcpy_tofs (&(buf)[0], &status_buf[status_ptr], l); status_ptr += l; return l; @@ -367,7 +357,7 @@ printk ("Sound: Undefined minor device %d\n", dev); } - return -EPERM; + return -(EPERM); } int @@ -401,77 +391,67 @@ } - return -EPERM; + return -(EPERM); } int sound_open_sw (int dev, struct fileinfo *file) { + int retval; + DEB (printk ("sound_open_sw(dev=%d)\n", dev)); if ((dev >= SND_NDEVS) || (dev < 0)) { printk ("Invalid minor device %d\n", dev); - return -ENXIO; + return -(ENXIO); } switch (dev & 0x0f) { case SND_DEV_STATUS: if (status_busy) - return -EBUSY; + return -(EBUSY); status_busy = 1; - if ((status_buf = (char *) kmalloc (4000, GFP_KERNEL)) == NULL) - return -EIO; + if ((status_buf = (char *) vmalloc (4000)) == NULL) + return -(EIO); status_len = status_ptr = 0; init_status (); break; case SND_DEV_CTL: if ((dev & 0xf0) && ((dev & 0xf0) >> 4) >= num_mixers) - return -ENXIO; + return -(ENXIO); return 0; break; #ifdef CONFIG_SEQUENCER case SND_DEV_SEQ: case SND_DEV_SEQ2: - { - int retval; - if ((retval = sequencer_open (dev, file)) < 0) return retval; break; - } #endif #ifdef CONFIG_MIDI case SND_DEV_MIDIN: - { - int retval; - if ((retval = MIDIbuf_open (dev, file)) < 0) return retval; break; - } #endif #ifdef CONFIG_AUDIO case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: - { - int retval; - if ((retval = audio_open (dev, file)) < 0) return retval; break; - } #endif default: printk ("Invalid minor device %d\n", dev); - return -ENXIO; + return -(ENXIO); } in_use++; @@ -489,7 +469,7 @@ { case SND_DEV_STATUS: if (status_buf) - kfree (status_buf); + vfree (status_buf); status_buf = NULL; status_busy = 0; break; @@ -524,6 +504,21 @@ in_use--; } +static int +get_mixer_info (int dev, caddr_t arg) +{ + mixer_info info; + + if (dev < 0 || dev >= num_mixers) + return -(ENXIO); + + strcpy (info.id, mixer_devs[dev]->id); + strcpy (info.name, mixer_devs[dev]->name); + + memcpy_tofs (&((char *) arg)[0], (char *) &info, sizeof (info)); + return 0; +} + int sound_ioctl_sw (int dev, struct fileinfo *file, unsigned int cmd, caddr_t arg) @@ -533,22 +528,29 @@ if (((cmd >> 8) & 0xff) == 'M' && num_mixers > 0) /* Mixer ioctl */ if ((dev & 0x0f) != SND_DEV_CTL) { -#ifdef CONFIG_AUDIO int dtype = dev & 0x0f; int mixdev; switch (dtype) { +#ifdef CONFIG_AUDIO case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: mixdev = audio_devs[dev >> 4]->mixer_dev; if (mixdev < 0 || mixdev >= num_mixers) - return -ENXIO; + return -(ENXIO); + if (cmd == SOUND_MIXER_INFO) + return get_mixer_info (mixdev, arg); return mixer_devs[mixdev]->ioctl (mixdev, cmd, arg); - } + break; #endif - return mixer_devs[0]->ioctl (0, cmd, arg); + + default: + if (cmd == SOUND_MIXER_INFO) + return get_mixer_info (0, arg); + return mixer_devs[0]->ioctl (0, cmd, arg); + } } switch (dev & 0x0f) @@ -557,13 +559,15 @@ case SND_DEV_CTL: if (!num_mixers) - return -ENXIO; + return -(ENXIO); dev = dev >> 4; if (dev >= num_mixers) - return -ENXIO; + return -(ENXIO); + if (cmd == SOUND_MIXER_INFO) + return get_mixer_info (dev, arg); return mixer_devs[dev]->ioctl (dev, cmd, arg); break; @@ -590,5 +594,5 @@ } - return -EPERM; + return -(EPERM); } diff -ur --new-file old/linux/drivers/sound/sound_timer.c new/linux/drivers/sound/sound_timer.c --- old/linux/drivers/sound/sound_timer.c Sun Mar 24 21:50:24 1996 +++ new/linux/drivers/sound/sound_timer.c Sun Aug 18 09:46:49 1996 @@ -2,27 +2,11 @@ * sound/sound_timer.c */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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 @@ -110,7 +94,7 @@ timer_open (int dev, int mode) { if (opened) - return -EBUSY; + return -(EBUSY); tmr_reset (); curr_tempo = 60; @@ -230,7 +214,7 @@ case SNDCTL_TMR_TIMEBASE: { - int val = get_fs_long ((long *) arg); + int val = get_user ((int *) arg); if (val) { @@ -247,7 +231,7 @@ case SNDCTL_TMR_TEMPO: { - int val = get_fs_long ((long *) arg); + int val = get_user ((int *) arg); if (val) { @@ -267,8 +251,8 @@ break; case SNDCTL_SEQ_CTRLRATE: - if (get_fs_long ((long *) arg) != 0) /* Can't change */ - return -EINVAL; + if (get_user ((int *) arg) != 0) /* Can't change */ + return -(EINVAL); return snd_ioctl_return ((int *) arg, ((curr_tempo * curr_timebase) + 30) / 60); break; @@ -280,7 +264,7 @@ default:; } - return -EINVAL; + return -(EINVAL); } static void diff -ur --new-file old/linux/drivers/sound/soundcard.c new/linux/drivers/sound/soundcard.c --- old/linux/drivers/sound/soundcard.c Wed May 15 08:09:00 1996 +++ new/linux/drivers/sound/soundcard.c Tue Aug 20 12:49:01 1996 @@ -4,27 +4,11 @@ * Soundcard driver for Linux */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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 @@ -33,6 +17,8 @@ #include + +int *sound_global_osp = NULL; static int chrdev_registered = 0; static int sound_major = SOUND_MAJOR; @@ -42,7 +28,7 @@ * Table for permanently allocated memory (used when unloading the module) */ caddr_t sound_mem_blocks[1024]; -int sound_num_blocks = 0; +int sound_nblocks = 0; static int soundcard_configured = 0; @@ -55,13 +41,14 @@ #define DMA_MAP_FREE 1 #define DMA_MAP_BUSY 2 + int snd_ioctl_return (int *addr, int value) { if (value < 0) return value; - put_fs_long (value, (long *) &((addr)[0])); + put_user (value, addr); return 0; } @@ -92,7 +79,7 @@ static int sound_lseek (inode_handle * inode, file_handle * file, off_t offset, int orig) { - return -EPERM; + return -(EPERM); } static int @@ -104,15 +91,15 @@ if (is_unloading) { printk ("Sound: Driver partially removed. Can't open device\n"); - return -EBUSY; + return -(EBUSY); } dev = MINOR (inode_get_rdev (inode)); if (!soundcard_configured && dev != SND_DEV_CTL && dev != SND_DEV_STATUS) { - printk ("SoundCard Error: The soundcard system has not been configured\n"); - return -ENXIO; + printk ("Sound Card Error: The soundcard system has not been configured\n"); + return -(ENXIO); } tmp_file.mode = 0; @@ -302,8 +289,7 @@ size, dmap->bytes_in_use); } - - if (remap_page_range (vma_get_start (vma), dmap->raw_buf_phys, + if (remap_page_range (vma_get_start (vma), (unsigned long)dmap->raw_buf, vma_get_end (vma) - vma_get_start (vma), vma_get_page_prot (vma))) return -EAGAIN; @@ -342,8 +328,17 @@ soundcard_configured = 1; - sndtable_init (0); /* Initialize call tables and - * detect cards */ + sndtable_init (); /* Initialize call tables and detect cards */ + + + +#ifdef CONFIG_LOWLEVEL_SOUND + { + extern void sound_init_lowlevel_drivers (void); + + sound_init_lowlevel_drivers (); + } +#endif if (sndtable_get_cardcount () == 0) return; /* No cards detected */ @@ -351,19 +346,19 @@ #ifdef CONFIG_AUDIO if (num_audiodevs) /* Audio devices present */ { - DMAbuf_init (0); - audio_init (0); + DMAbuf_init (); + audio_init (); } #endif #ifdef CONFIG_MIDI if (num_midis) - MIDIbuf_init (0); + MIDIbuf_init (); #endif #ifdef CONFIG_SEQUENCER if (num_midis + num_synths) - sequencer_init (0); + sequencer_init (); #endif } @@ -389,6 +384,8 @@ #endif +static int debugmem = 0; /* switched off by default */ + static int sound[20] = {0}; @@ -426,7 +423,7 @@ chrdev_registered = 1; soundcard_init (); - if (sound_num_blocks >= 1024) + if (sound_nblocks >= 1024) printk ("Sound warning: Deallocation table was too small.\n"); return 0; @@ -440,16 +437,29 @@ { int i; + if (MOD_IN_USE) + { + return; + } + if (chrdev_registered) module_unregister_chrdev (sound_major, "sound"); #ifdef CONFIG_SEQUENCER sound_stop_timer (); #endif + +#ifdef CONFIG_LOWLEVEL_SOUND + { + extern void sound_unload_lowlevel_drivers (void); + + sound_unload_lowlevel_drivers (); + } +#endif sound_unload_drivers (); - for (i = 0; i < sound_num_blocks; i++) - kfree (sound_mem_blocks[i]); + for (i = 0; i < sound_nblocks; i++) + vfree (sound_mem_blocks[i]); free_all_irqs (); /* If something was left allocated by accident */ @@ -460,6 +470,7 @@ sound_free_dma (i); } + } #endif @@ -473,11 +484,15 @@ } int -snd_set_irq_handler (int interrupt_level, void (*hndlr) (int, void *, struct pt_regs *), char *name, int *osp) +snd_set_irq_handler (int interrupt_level, void (*iproc) (int, void *, struct pt_regs *), char *name, int *osp) { int retcode; + unsigned long flags; + + save_flags (flags); + cli (); - retcode = request_irq (interrupt_level, hndlr, 0 /* SA_INTERRUPT */ , name, NULL); + retcode = request_irq (interrupt_level, iproc, 0 /* SA_INTERRUPT */ , name, NULL); if (retcode < 0) { printk ("Sound: IRQ%d already in use\n", interrupt_level); @@ -485,6 +500,7 @@ else irqs |= (1ul << interrupt_level); + restore_flags (flags); return retcode; } @@ -516,6 +532,12 @@ { unsigned long flags; + if (chn < 0 || chn > 7 || chn == 4) + { + printk ("sound_open_dma: Invalid DMA channel %d\n", chn); + return 1; + } + save_flags (flags); cli (); @@ -598,8 +620,6 @@ fatal_error__This_version_is_not_compatible_with_this_kernel; #endif -static int debugmem = 0; /* switched off by default */ - static int dma_buffsize = DSP_BUFFSIZE; int @@ -648,14 +668,14 @@ audio_devs[dev]->buffsize = PAGE_SIZE * (1 << sz); - if ((start_addr = (char *) __get_free_pages (GFP_ATOMIC, sz, MAX_DMA_ADDRESS)) == NULL) + if ((start_addr = (char *) __get_dma_pages (GFP_ATOMIC, sz)) == NULL) audio_devs[dev]->buffsize /= 2; } if (start_addr == NULL) { printk ("Sound error: Couldn't allocate DMA buffer\n"); - return -ENOMEM; + return -(ENOMEM); } else { @@ -673,10 +693,10 @@ || end_addr >= (char *) (MAX_DMA_ADDRESS)) { printk ( - "sound: kmalloc returned invalid address 0x%lx for %ld Bytes DMA-buffer\n", + "sound: Got invalid address 0x%lx for %ldb DMA-buffer\n", (long) start_addr, audio_devs[dev]->buffsize); - return -EFAULT; + return -(EFAULT); } } dmap->raw_buf = start_addr; @@ -693,30 +713,28 @@ void sound_free_dmap (int dev, struct dma_buffparms *dmap) { + int sz, size, i; + unsigned long start_addr, end_addr; + if (dmap->raw_buf == NULL) return; if (dmap->mapping_flags & DMA_MAP_MAPPED) return; /* Don't free mmapped buffer. Will use it next time */ - { - int sz, size, i; - unsigned long start_addr, end_addr; + for (sz = 0, size = PAGE_SIZE; + size < audio_devs[dev]->buffsize; + sz++, size <<= 1); - for (sz = 0, size = PAGE_SIZE; - size < audio_devs[dev]->buffsize; - sz++, size <<= 1); + start_addr = (unsigned long) dmap->raw_buf; + end_addr = start_addr + audio_devs[dev]->buffsize; - start_addr = (unsigned long) dmap->raw_buf; - end_addr = start_addr + audio_devs[dev]->buffsize; - - for (i = MAP_NR (start_addr); i <= MAP_NR (end_addr); i++) - { - mem_map_unreserve (i); - } + for (i = MAP_NR (start_addr); i <= MAP_NR (end_addr); i++) + { + mem_map_unreserve (i); + } - free_pages ((unsigned long) dmap->raw_buf, sz); - } + free_pages ((unsigned long) dmap->raw_buf, sz); dmap->raw_buf = NULL; } @@ -725,7 +743,7 @@ { printk ("Entered sound_map_buffer()\n"); printk ("Exited sound_map_buffer()\n"); - return -EINVAL; + return -(EINVAL); } #endif diff -ur --new-file old/linux/drivers/sound/soundvers.h new/linux/drivers/sound/soundvers.h --- old/linux/drivers/sound/soundvers.h Sat Mar 30 12:38:31 1996 +++ new/linux/drivers/sound/soundvers.h Mon Jul 1 05:30:35 1996 @@ -1,2 +1,2 @@ -#define SOUND_VERSION_STRING "3.5.2-960330" -#define SOUND_INTERNAL_VERSION 0x030500 +#define SOUND_VERSION_STRING "3.5.4-960630" +#define SOUND_INTERNAL_VERSION 0x030504 diff -ur --new-file old/linux/drivers/sound/sscape.c new/linux/drivers/sound/sscape.c --- old/linux/drivers/sound/sscape.c Sat Apr 13 10:21:38 1996 +++ new/linux/drivers/sound/sscape.c Sun Jul 7 10:19:01 1996 @@ -1,30 +1,14 @@ /* * sound/sscape.c * - * Low level driver for Ensoniq Soundscape + * Low level driver for Ensoniq SoundScape */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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 @@ -281,7 +265,7 @@ host_command3 (devc, CMD_SET_CONTROL, ctrl, value); if (host_read (devc) != CMD_ACK) { - printk ("SNDSCAPE: Setting control (%d) failed\n", ctrl); + /* printk ("SNDSCAPE: Setting control (%d) failed\n", ctrl); */ } host_close (devc); } @@ -307,10 +291,10 @@ static int debug = 0; bits = sscape_read (devc, GA_INTSTAT_REG); - if ((sscape_sleep_flag.mode & WK_SLEEP)) + if ((sscape_sleep_flag.flags & WK_SLEEP)) { { - sscape_sleep_flag.mode = WK_WAKEUP; + sscape_sleep_flag.flags = WK_WAKEUP; module_wake_up (&sscape_sleeper); }; } @@ -320,7 +304,7 @@ printk ("SSCAPE: Host interrupt, data=%02x\n", host_read (devc)); } -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) +#if defined(CONFIG_MPU_EMU) && defined(CONFIG_MIDI) if (bits & 0x01) { mpuintr (irq, NULL, NULL); @@ -352,9 +336,11 @@ return; } + audio_devs[devc->my_audiodev]->flags &= ~DMA_AUTOMODE; DMAbuf_start_dma (devc->my_audiodev, buf, blk_size, mode); + audio_devs[devc->my_audiodev]->flags |= DMA_AUTOMODE; temp = devc->dma << 4; /* Setup DMA channel select bits */ if (devc->dma <= 3) @@ -401,10 +387,10 @@ { set_mt32 (devc, 0); if (!verify_mpu (devc)) - return -EIO; + return -(EIO); } - sscape_sleep_flag.mode = WK_NONE; + sscape_sleep_flag.flags = WK_NONE; return 0; } @@ -419,11 +405,9 @@ if (devc->dma_allocated) { sscape_write (devc, GA_DMAA_REG, 0x20); /* DMA channel disabled */ -#ifdef CONFIG_NATIVE_PCM -#endif devc->dma_allocated = 0; } - sscape_sleep_flag.mode = WK_NONE; + sscape_sleep_flag.flags = WK_NONE; restore_flags (flags); return; @@ -440,7 +424,7 @@ unsigned long flags; unsigned char temp; int done, timeout_val; - static int already_done = 0; + static unsigned char codec_dma_bits = 0; if (flag & CPF_FIRST) { @@ -449,20 +433,16 @@ * before continuing. */ - if (already_done) - { - printk ("Can't run 'ssinit' twice\n"); - return 0; - } - already_done = 1; - save_flags (flags); cli (); - if (devc->dma_allocated == 0) - { -#ifdef CONFIG_NATIVE_PCM + codec_dma_bits = sscape_read (devc, GA_CDCFG_REG); +#if 0 + sscape_write (devc, GA_CDCFG_REG, + codec_dma_bits & ~0x08); /* Disable codec DMA */ #endif + if (devc->dma_allocated == 0) + { devc->dma_allocated = 1; } restore_flags (flags); @@ -479,7 +459,7 @@ } /* - * Transfer one code block using DMA + * Transfer one code block using DMA */ memcpy (audio_devs[devc->my_audiodev]->dmap_out->raw_buf, block, size); @@ -493,7 +473,7 @@ /* * Wait until transfer completes. */ - sscape_sleep_flag.mode = WK_NONE; + sscape_sleep_flag.flags = WK_NONE; done = 0; timeout_val = 100; while (!done && timeout_val-- > 0) @@ -502,24 +482,26 @@ { - unsigned long tl; + unsigned long tlimit; if (1) - current_set_timeout (tl = jiffies + (1)); + current_set_timeout (tlimit = jiffies + (1)); else - tl = (unsigned long) -1; - sscape_sleep_flag.mode = WK_SLEEP; + tlimit = (unsigned long) -1; + sscape_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&sscape_sleeper); - if (!(sscape_sleep_flag.mode & WK_WAKEUP)) + if (!(sscape_sleep_flag.flags & WK_WAKEUP)) { - if (jiffies >= tl) - sscape_sleep_flag.mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + sscape_sleep_flag.flags |= WK_TIMEOUT; } - sscape_sleep_flag.mode &= ~WK_SLEEP; + sscape_sleep_flag.flags &= ~WK_SLEEP; }; clear_dma_ff (devc->dma); if ((resid = get_dma_residue (devc->dma)) == 0) - done = 1; + { + done = 1; + } } restore_flags (flags); @@ -550,24 +532,26 @@ { { - unsigned long tl; + unsigned long tlimit; if (1) - current_set_timeout (tl = jiffies + (1)); + current_set_timeout (tlimit = jiffies + (1)); else - tl = (unsigned long) -1; - sscape_sleep_flag.mode = WK_SLEEP; + tlimit = (unsigned long) -1; + sscape_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&sscape_sleeper); - if (!(sscape_sleep_flag.mode & WK_WAKEUP)) + if (!(sscape_sleep_flag.flags & WK_WAKEUP)) { - if (jiffies >= tl) - sscape_sleep_flag.mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + sscape_sleep_flag.flags |= WK_TIMEOUT; } - sscape_sleep_flag.mode &= ~WK_SLEEP; + sscape_sleep_flag.flags &= ~WK_SLEEP; }; if (inb (PORT (HOST_DATA)) == 0xff) /* OBP startup acknowledge */ done = 1; } + sscape_write (devc, GA_CDCFG_REG, codec_dma_bits); + restore_flags (flags); if (!done) { @@ -583,20 +567,20 @@ { { - unsigned long tl; + unsigned long tlimit; if (1) - current_set_timeout (tl = jiffies + (1)); + current_set_timeout (tlimit = jiffies + (1)); else - tl = (unsigned long) -1; - sscape_sleep_flag.mode = WK_SLEEP; + tlimit = (unsigned long) -1; + sscape_sleep_flag.flags = WK_SLEEP; module_interruptible_sleep_on (&sscape_sleeper); - if (!(sscape_sleep_flag.mode & WK_WAKEUP)) + if (!(sscape_sleep_flag.flags & WK_WAKEUP)) { - if (jiffies >= tl) - sscape_sleep_flag.mode |= WK_TIMEOUT; + if (jiffies >= tlimit) + sscape_sleep_flag.flags |= WK_TIMEOUT; } - sscape_sleep_flag.mode &= ~WK_SLEEP; + sscape_sleep_flag.flags &= ~WK_SLEEP; }; if (inb (PORT (HOST_DATA)) == 0xfe) /* Host startup acknowledge */ done = 1; @@ -636,12 +620,12 @@ download_boot_block (void *dev_info, copr_buffer * buf) { if (buf->len <= 0 || buf->len > sizeof (buf->data)) - return -EINVAL; + return -(EINVAL); if (!sscape_download_boot (devc, buf->data, buf->len, buf->flags)) { printk ("SSCAPE: Unable to load microcode block to the OBP.\n"); - return -EIO; + return -(EIO); } return 0; @@ -663,18 +647,18 @@ copr_buffer *buf; int err; - buf = (copr_buffer *) kmalloc (sizeof (copr_buffer), GFP_KERNEL); + buf = (copr_buffer *) vmalloc (sizeof (copr_buffer)); if (buf == NULL) - return -ENOSPC; - memcpy_fromfs ((char *) buf, &(((char *) arg)[0]), sizeof (*buf)); + return -(ENOSPC); + memcpy_fromfs ((char *) buf, &((char *) arg)[0], sizeof (*buf)); err = download_boot_block (dev_info, buf); - kfree (buf); + vfree (buf); return err; } break; default: - return -EINVAL; + return -(EINVAL); } } @@ -689,176 +673,11 @@ &dev_info }; -static int -sscape_audio_open (int dev, int mode) -{ - unsigned long flags; - sscape_info *devc = (sscape_info *) audio_devs[dev]->devc; - - save_flags (flags); - cli (); - if (devc->opened) - { - restore_flags (flags); - return -EBUSY; - } - devc->opened = 1; - restore_flags (flags); -#ifdef SSCAPE_DEBUG4 - /* - * Temporary debugging aid. Print contents of the registers - * when the device is opened. - */ - { - int i; - - for (i = 0; i < 13; i++) - printk ("I%d = %02x\n", i, sscape_read (devc, i)); - } -#endif - - return 0; -} - -static void -sscape_audio_close (int dev) -{ - unsigned long flags; - sscape_info *devc = (sscape_info *) audio_devs[dev]->devc; - - DEB (printk ("sscape_audio_close(void)\n")); - - save_flags (flags); - cli (); - - devc->opened = 0; - - restore_flags (flags); -} - -static int -set_speed (sscape_info * devc, int arg) -{ - return 8000; -} - -static int -set_channels (sscape_info * devc, int arg) -{ - return 1; -} - -static int -set_format (sscape_info * devc, int arg) -{ - return AFMT_U8; -} - -static int -sscape_audio_ioctl (int dev, unsigned int cmd, caddr_t arg, int local) -{ - sscape_info *devc = (sscape_info *) audio_devs[dev]->devc; - - switch (cmd) - { - case SOUND_PCM_WRITE_RATE: - if (local) - return set_speed (devc, (int) arg); - return snd_ioctl_return ((int *) arg, set_speed (devc, get_fs_long ((long *) arg))); - - case SOUND_PCM_READ_RATE: - if (local) - return 8000; - return snd_ioctl_return ((int *) arg, 8000); - - case SNDCTL_DSP_STEREO: - if (local) - return set_channels (devc, (int) arg + 1) - 1; - return snd_ioctl_return ((int *) arg, set_channels (devc, get_fs_long ((long *) arg) + 1) - 1); - - case SOUND_PCM_WRITE_CHANNELS: - if (local) - return set_channels (devc, (int) arg); - return snd_ioctl_return ((int *) arg, set_channels (devc, get_fs_long ((long *) arg))); - - case SOUND_PCM_READ_CHANNELS: - if (local) - return 1; - return snd_ioctl_return ((int *) arg, 1); - - case SNDCTL_DSP_SAMPLESIZE: - if (local) - return set_format (devc, (int) arg); - return snd_ioctl_return ((int *) arg, set_format (devc, get_fs_long ((long *) arg))); - - case SOUND_PCM_READ_BITS: - if (local) - return 8; - return snd_ioctl_return ((int *) arg, 8); - - default:; - } - return -EINVAL; -} - -static void -sscape_audio_output_block (int dev, unsigned long buf, int count, int intrflag, int dma_restart) -{ -} - -static void -sscape_audio_start_input (int dev, unsigned long buf, int count, int intrflag, int dma_restart) -{ -} - -static int -sscape_audio_prepare_for_input (int dev, int bsize, int bcount) -{ - return 0; -} - -static int -sscape_audio_prepare_for_output (int dev, int bsize, int bcount) -{ - return 0; -} - -static void -sscape_audio_halt (int dev) -{ -} - -static void -sscape_audio_reset (int dev) -{ - sscape_audio_halt (dev); -} - -static struct audio_operations sscape_audio_operations = -{ - "Not functional", - 0, - AFMT_U8 | AFMT_S16_LE, - NULL, - sscape_audio_open, - sscape_audio_close, - sscape_audio_output_block, - sscape_audio_start_input, - sscape_audio_ioctl, - sscape_audio_prepare_for_input, - sscape_audio_prepare_for_output, - sscape_audio_reset, - sscape_audio_halt, - NULL, - NULL -}; - static int sscape_detected = 0; -long -attach_sscape (long mem_start, struct address_info *hw_config) +void +attach_sscape (struct address_info *hw_config) { - int my_dev; #ifndef SSCAPE_REGS /* @@ -894,15 +713,15 @@ int i, irq_bits = 0xff; if (sscape_detected != hw_config->io_base) - return mem_start; + return; if (old_hardware) { valid_interrupts = valid_interrupts_old; - conf_printf ("Ensoniq Soundscape (old)", hw_config); + conf_printf ("Ensoniq SoundScape (old)", hw_config); } else - conf_printf ("Ensoniq Soundscape", hw_config); + conf_printf ("Ensoniq SoundScape", hw_config); for (i = 0; i < sizeof (valid_interrupts); i++) if (hw_config->irq == valid_interrupts[i]) @@ -914,7 +733,7 @@ if (hw_config->irq > 15 || (regs[4] = irq_bits == 0xff)) { printk ("Invalid IRQ%d\n", hw_config->irq); - return mem_start; + return; } save_flags (flags); @@ -975,38 +794,20 @@ int prev_devs; prev_devs = num_midis; - mem_start = attach_mpu401 (mem_start, hw_config); + hw_config->name = "SoundScape"; + + hw_config->irq *= -1; /* Negative value signals IRQ sharing */ + attach_mpu401 (hw_config); + hw_config->irq *= -1; /* Restore it */ if (num_midis == (prev_devs + 1)) /* The MPU driver installed itself */ midi_devs[prev_devs]->coproc = &sscape_coproc_operations; } #endif -#ifndef EXCLUDE_NATIVE_PCM - /* Not supported yet */ - -#ifdef CONFIG_AUDIO - if (num_audiodevs < MAX_AUDIO_DEV) - { - audio_devs[my_dev = num_audiodevs++] = &sscape_audio_operations; - audio_devs[my_dev]->dmachan1 = hw_config->dma; - audio_devs[my_dev]->buffsize = DSP_BUFFSIZE; - audio_devs[my_dev]->devc = devc; - devc->my_audiodev = my_dev; - devc->opened = 0; - audio_devs[my_dev]->coproc = &sscape_coproc_operations; - if (snd_set_irq_handler (hw_config->irq, sscapeintr, "SoundScape", devc->osp) < 0) - printk ("Error: Can't allocate IRQ for SoundScape\n"); - - sscape_write (devc, GA_INTENA_REG, 0x80); /* Master IRQ enable */ - } - else - printk ("SoundScape: More than enough audio devices detected\n"); -#endif -#endif + sscape_write (devc, GA_INTENA_REG, 0x80); /* Master IRQ enable */ devc->ok = 1; devc->failed = 0; - return mem_start; } int @@ -1025,7 +826,7 @@ /* * First check that the address register of "ODIE" is - * there and that it has exactly 4 writeable bits. + * there and that it has exactly 4 writable bits. * First 4 bits */ if ((save = inb (PORT (ODIE_ADDR))) & 0xf0) @@ -1083,11 +884,6 @@ old_hardware = 0; } - if (sound_alloc_dma (hw_config->dma, "soundscape")) - { - printk ("sscape.c: Can't allocate DMA channel\n"); - return 0; - } sscape_detected = hw_config->io_base; @@ -1123,8 +919,8 @@ return ad1848_detect (hw_config->io_base, NULL, hw_config->osp); } -long -attach_ss_ms_sound (long mem_start, struct address_info *hw_config) +void +attach_ss_ms_sound (struct address_info *hw_config) { /* * This routine configures the SoundScape card for use with the @@ -1134,13 +930,12 @@ int i, irq_bits = 0xff; -#ifndef CONFIG_NATIVE_PCM int prev_devs = num_audiodevs; -#endif + hw_config->dma = devc->dma; /* Share the DMA with the ODIE/OPUS chip */ /* - * Setup the DMA polarity. + * Setup the DMA polarity. */ sscape_write (devc, GA_DMACFG_REG, 0x50); @@ -1173,10 +968,10 @@ 0, devc->osp); -#ifndef CONFIG_NATIVE_PCM if (num_audiodevs == (prev_devs + 1)) /* The AD1848 driver installed itself */ audio_devs[prev_devs]->coproc = &sscape_coproc_operations; -#endif + devc->my_audiodev = prev_devs; + #ifdef SSCAPE_DEBUG5 /* * Temporary debugging aid. Print contents of the registers @@ -1190,17 +985,15 @@ } #endif - return mem_start; } void unload_sscape (struct address_info *hw_config) { -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) +#if defined(CONFIG_MPU_EMU) && defined(CONFIG_MIDI) unload_mpu401 (hw_config); #endif snd_release_irq (hw_config->irq); - sound_free_dma (hw_config->dma); } void @@ -1208,9 +1001,10 @@ { ad1848_unload (hw_config->io_base, hw_config->irq, - hw_config->dma, - hw_config->dma, + devc->dma, + devc->dma, 0); } + #endif diff -ur --new-file old/linux/drivers/sound/sys_timer.c new/linux/drivers/sound/sys_timer.c --- old/linux/drivers/sound/sys_timer.c Sun Mar 24 21:50:27 1996 +++ new/linux/drivers/sound/sys_timer.c Sun Aug 18 09:46:49 1996 @@ -5,27 +5,11 @@ * Uses the (1/HZ sec) timer of kernel. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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 @@ -106,7 +90,7 @@ def_tmr_open (int dev, int mode) { if (opened) - return -EBUSY; + return -(EBUSY); tmr_reset (); curr_tempo = 60; @@ -229,7 +213,7 @@ case SNDCTL_TMR_TIMEBASE: { - int val = get_fs_long ((long *) arg); + int val = get_user ((int *) arg); if (val) { @@ -246,7 +230,7 @@ case SNDCTL_TMR_TEMPO: { - int val = get_fs_long ((long *) arg); + int val = get_user ((int *) arg); if (val) { @@ -265,8 +249,8 @@ break; case SNDCTL_SEQ_CTRLRATE: - if (get_fs_long ((long *) arg) != 0) /* Can't change */ - return -EINVAL; + if (get_user ((int *) arg) != 0) /* Can't change */ + return -(EINVAL); return snd_ioctl_return ((int *) arg, ((curr_tempo * curr_timebase) + 30) / 60); break; @@ -278,7 +262,7 @@ default:; } - return -EINVAL; + return -(EINVAL); } static void diff -ur --new-file old/linux/drivers/sound/trix.c new/linux/drivers/sound/trix.c --- old/linux/drivers/sound/trix.c Sun Mar 24 21:50:28 1996 +++ new/linux/drivers/sound/trix.c Sat Jul 20 07:56:29 1996 @@ -1,36 +1,21 @@ /* * sound/trix.c * - * Low level driver for the MediaTriX AudioTriX Pro + * Low level driver for the MediaTrix AudioTrix Pro * (MT-0002-PC Control Chip) */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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 "sound_config.h" +#include "sb.h" #if defined(CONFIG_TRIX) @@ -98,16 +83,16 @@ if (check_region (0x390, 2)) { - printk ("AudioTriX: Config port I/O conflict\n"); + printk ("AudioTrix: Config port I/O conflict\n"); return 0; } if (kilroy_was_here) /* Already initialized */ return 0; - if (trix_read (0x15) != 0x71) /* No asic signature */ + if (trix_read (0x15) != 0x71) /* No ASIC signature */ { - DDB (printk ("No AudioTriX ASIC signature found\n")); + DDB (printk ("No AudioTrix ASIC signature found\n")); return 0; } @@ -148,7 +133,7 @@ /* * Probe and attach routines for the Windows Sound System mode of - * AudioTriX Pro + * AudioTrix Pro */ int @@ -158,12 +143,12 @@ /* * Check if the IO port returns valid signature. The original MS Sound - * system returns 0x04 while some cards (AudioTriX Pro for example) + * system returns 0x04 while some cards (AudioTrix Pro for example) * return 0x00. */ if (check_region (hw_config->io_base, 8)) { - printk ("AudioTriX: MSS I/O port conflict (%x)\n", hw_config->io_base); + printk ("AudioTrix: MSS I/O port conflict (%x)\n", hw_config->io_base); return 0; } @@ -180,20 +165,20 @@ if (hw_config->irq > 11) { - printk ("AudioTriX: Bad WSS IRQ %d\n", hw_config->irq); + printk ("AudioTrix: Bad WSS IRQ %d\n", hw_config->irq); return 0; } if (hw_config->dma != 0 && hw_config->dma != 1 && hw_config->dma != 3) { - printk ("AudioTriX: Bad WSS DMA %d\n", hw_config->dma); + printk ("AudioTrix: Bad WSS DMA %d\n", hw_config->dma); return 0; } if (hw_config->dma2 != -1) if (hw_config->dma2 != 0 && hw_config->dma2 != 1 && hw_config->dma2 != 3) { - printk ("AudioTriX: Bad capture DMA %d\n", hw_config->dma2); + printk ("AudioTrix: Bad capture DMA %d\n", hw_config->dma2); return 0; } @@ -203,43 +188,43 @@ if (hw_config->dma == 0 && inb (hw_config->io_base + 3) & 0x80) { - printk ("AudioTriX: Can't use DMA0 with a 8 bit card\n"); + printk ("AudioTrix: Can't use DMA0 with a 8 bit card\n"); return 0; } if (hw_config->irq > 7 && hw_config->irq != 9 && inb (hw_config->io_base + 3) & 0x80) { - printk ("AudioTriX: Can't use IRQ%d with a 8 bit card\n", hw_config->irq); + printk ("AudioTrix: Can't use IRQ%d with a 8 bit card\n", hw_config->irq); return 0; } ret = ad1848_detect (hw_config->io_base + 4, NULL, hw_config->osp); if (ret) - request_region (0x390, 2, "AudioTriX"); + request_region (0x390, 2, "AudioTrix"); return ret; } -long -attach_trix_wss (long mem_start, struct address_info *hw_config) +void +attach_trix_wss (struct address_info *hw_config) { static unsigned char interrupt_bits[12] = - {-1, -1, -1, -1, -1, -1, -1, 0x08, -1, 0x10, 0x18, 0x20}; + {0, 0, 0, 0, 0, 0, 0, 0x08, 0, 0x10, 0x18, 0x20}; char bits; static unsigned char dma_bits[4] = {1, 2, 0, 3}; - int config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3; + int config_port = hw_config->io_base + 0; int dma1 = hw_config->dma, dma2 = hw_config->dma2; trix_osp = hw_config->osp; if (!kilroy_was_here) { - DDB (printk ("AudioTriX: Attach called but not probed yet???\n")); - return mem_start; + DDB (printk ("AudioTrix: Attach called but not probed yet???\n")); + return; } /* @@ -247,17 +232,15 @@ */ bits = interrupt_bits[hw_config->irq]; - if (bits == -1) + if (bits == 0) { - printk ("AudioTriX: Bad IRQ (%d)\n", hw_config->irq); - return mem_start; + printk ("AudioTrix: Bad IRQ (%d)\n", hw_config->irq); + return; } outb (bits | 0x40, config_port); - if ((inb (version_port) & 0x40) == 0) - printk ("[IRQ Conflict?]"); - if (hw_config->dma2 == -1) /* Single DMA mode */ + if (hw_config->dma2 == -1 || hw_config->dma2 == hw_config->dma) { bits |= dma_bits[dma1]; dma2 = dma1; @@ -275,14 +258,13 @@ outb (bits, config_port); /* Write IRQ+DMA setup */ - ad1848_init ("AudioTriX Pro", hw_config->io_base + 4, + ad1848_init ("AudioTrix Pro", hw_config->io_base + 4, hw_config->irq, dma1, dma2, 0, hw_config->osp); request_region (hw_config->io_base, 4, "MSS config"); - return mem_start; } int @@ -298,18 +280,18 @@ return 0; /* No boot code -> no fun */ if (!kilroy_was_here) - return 0; /* AudioTriX Pro has not been detected earlier */ + return 0; /* AudioTrix Pro has not been detected earlier */ if (sb_initialized) return 0; if (check_region (hw_config->io_base, 16)) { - printk ("AudioTriX: SB I/O port conflict (%x)\n", hw_config->io_base); + printk ("AudioTrix: SB I/O port conflict (%x)\n", hw_config->io_base); return 0; } - if (hw_config->io_base & 0xffffff8f != 0x200) + if ((hw_config->io_base & 0xffffff8f) != 0x200) return 0; tmp = hw_config->irq; @@ -332,36 +314,36 @@ download_boot (hw_config->io_base); sb_initialized = 1; - return 1; + hw_config->name = "AudioTrix SB"; +#ifdef CONFIG_SBDSP + return probe_sb (hw_config); +#else + return 0; +#endif } -long -attach_trix_sb (long mem_start, struct address_info *hw_config) +void +attach_trix_sb (struct address_info *hw_config) { -#ifdef CONFIG_SB - extern int sb_no_recording; - - sb_dsp_disable_midi (); - sb_no_recording = 1; +#ifdef CONFIG_SBDSP + hw_config->driver_use_1 = SB_NO_MIDI | SB_NO_MIXER | SB_NO_RECORDING; + attach_sb_card (hw_config); #endif - conf_printf ("AudioTriX (SB)", hw_config); - return mem_start; } -long -attach_trix_mpu (long mem_start, struct address_info *hw_config) +void +attach_trix_mpu (struct address_info *hw_config) { -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) - return attach_mpu401 (mem_start, hw_config); -#else - return mem_start; +#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) + hw_config->name = "AudioTrix Pro"; + attach_uart401 (hw_config); #endif } int probe_trix_mpu (struct address_info *hw_config) { -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) +#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) unsigned char conf; static char irq_bits[] = {-1, -1, -1, 1, 2, 3, -1, 4, -1, 5}; @@ -369,7 +351,7 @@ if (!kilroy_was_here) { DDB (printk ("Trix: WSS and SB modes must be initialized before MPU\n")); - return 0; /* AudioTriX Pro has not been detected earlier */ + return 0; /* AudioTrix Pro has not been detected earlier */ } if (!sb_initialized) @@ -386,19 +368,19 @@ if (check_region (hw_config->io_base, 4)) { - printk ("AudioTriX: MPU I/O port conflict (%x)\n", hw_config->io_base); + printk ("AudioTrix: MPU I/O port conflict (%x)\n", hw_config->io_base); return 0; } if (hw_config->irq > 9) { - printk ("AudioTriX: Bad MPU IRQ %d\n", hw_config->irq); + printk ("AudioTrix: Bad MPU IRQ %d\n", hw_config->irq); return 0; } if (irq_bits[hw_config->irq] == -1) { - printk ("AudioTriX: Bad MPU IRQ %d\n", hw_config->irq); + printk ("AudioTrix: Bad MPU IRQ %d\n", hw_config->irq); return 0; } @@ -426,7 +408,7 @@ mpu_initialized = 1; - return probe_mpu401 (hw_config); + return probe_uart401 (hw_config); #else return 0; #endif @@ -453,13 +435,16 @@ void unload_trix_mpu (struct address_info *hw_config) { -#if (defined(CONFIG_MPU401) || defined(CONFIG_MPU_EMU)) && defined(CONFIG_MIDI) - unload_mpu401 (hw_config); +#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) + unload_uart401 (hw_config); #endif } void unload_trix_sb (struct address_info *hw_config) { +#ifdef CONFIG_SBDSP + unload_sb (hw_config); +#endif } diff -ur --new-file old/linux/drivers/sound/uart401.c new/linux/drivers/sound/uart401.c --- old/linux/drivers/sound/uart401.c Thu Jan 1 01:00:00 1970 +++ new/linux/drivers/sound/uart401.c Wed Aug 14 09:21:03 1996 @@ -0,0 +1,439 @@ +/* + * sound/uart401.c + * + * MPU-401 UART driver (formerly uart401_midi.c) + */ +/* + * Copyright (C) by Hannu Savolainen 1993-1996 + * + * USS/Lite 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 "sound_config.h" + +#if defined(CONFIG_UART401) && defined(CONFIG_MIDI) + +typedef struct uart401_devc + { + int base; + int irq; + int *osp; + void (*midi_input_intr) (int dev, unsigned char data); + int opened; + volatile unsigned char input_byte; + int my_dev; + int share_irq; + } +uart401_devc; + +static uart401_devc *detected_devc = NULL; +static uart401_devc *irq2devc[16] = +{NULL}; + +#define DATAPORT (devc->base) +#define COMDPORT (devc->base+1) +#define STATPORT (devc->base+1) + +static int +uart401_status (uart401_devc * devc) +{ + return inb (STATPORT); +} +#define input_avail(devc) (!(uart401_status(devc)&INPUT_AVAIL)) +#define output_ready(devc) (!(uart401_status(devc)&OUTPUT_READY)) +static void +uart401_cmd (uart401_devc * devc, unsigned char cmd) +{ + outb (cmd, COMDPORT); +} +static int +uart401_read (uart401_devc * devc) +{ + return inb (DATAPORT); +} +static void +uart401_write (uart401_devc * devc, unsigned char byte) +{ + outb (byte, DATAPORT); +} + +#define OUTPUT_READY 0x40 +#define INPUT_AVAIL 0x80 +#define MPU_ACK 0xFE +#define MPU_RESET 0xFF +#define UART_MODE_ON 0x3F + +static int reset_uart401 (uart401_devc * devc); + +static void +uart401_input_loop (uart401_devc * devc) +{ + while (input_avail (devc)) + { + unsigned char c = uart401_read (devc); + + if (c == MPU_ACK) + devc->input_byte = c; + else if (devc->opened & OPEN_READ && devc->midi_input_intr) + devc->midi_input_intr (devc->my_dev, c); + } +} + +void +uart401intr (int irq, void *dev_id, struct pt_regs *dummy) +{ + uart401_devc *devc; + + if (irq < 1 || irq > 15) + return; + + devc = irq2devc[irq]; + + if (devc == NULL) + return; + + if (input_avail (devc)) + uart401_input_loop (devc); +} + +static int +uart401_open (int dev, int mode, + void (*input) (int dev, unsigned char data), + void (*output) (int dev) +) +{ + uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc; + + if (devc->opened) + { + return -(EBUSY); + } + + while (input_avail (devc)) + uart401_read (devc); + + devc->midi_input_intr = input; + devc->opened = mode; + + return 0; +} + +static void +uart401_close (int dev) +{ + uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc; + + devc->opened = 0; +} + +static int +uart401_out (int dev, unsigned char midi_byte) +{ + int timeout; + unsigned long flags; + uart401_devc *devc = (uart401_devc *) midi_devs[dev]->devc; + + /* + * Test for input since pending input seems to block the output. + */ + + save_flags (flags); + cli (); + + if (input_avail (devc)) + uart401_input_loop (devc); + + restore_flags (flags); + + /* + * Sometimes it takes about 13000 loops before the output becomes ready + * (After reset). Normally it takes just about 10 loops. + */ + + for (timeout = 30000; timeout > 0 && !output_ready (devc); timeout--); + + if (!output_ready (devc)) + { + printk ("MPU-401: Timeout\n"); + return 0; + } + + uart401_write (devc, midi_byte); + return 1; +} + +static int +uart401_start_read (int dev) +{ + return 0; +} + +static int +uart401_end_read (int dev) +{ + return 0; +} + +static int +uart401_ioctl (int dev, unsigned cmd, caddr_t arg) +{ + return -(EINVAL); +} + +static void +uart401_kick (int dev) +{ +} + +static int +uart401_buffer_status (int dev) +{ + return 0; +} + +#define MIDI_SYNTH_NAME "MPU-401 UART" +#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT +#include "midi_synth.h" + +static struct midi_operations uart401_operations = +{ + {"MPU-401 (UART) MIDI", 0, 0, SNDCARD_MPU401}, + &std_midi_synth, + {0}, + uart401_open, + uart401_close, + uart401_ioctl, + uart401_out, + uart401_start_read, + uart401_end_read, + uart401_kick, + NULL, + uart401_buffer_status, + NULL +}; + +static void +enter_uart_mode (uart401_devc * devc) +{ + int ok, timeout; + unsigned long flags; + + save_flags (flags); + cli (); + for (timeout = 30000; timeout < 0 && !output_ready (devc); timeout--); + + devc->input_byte = 0; + uart401_cmd (devc, UART_MODE_ON); + + ok = 0; + for (timeout = 50000; timeout > 0 && !ok; timeout--) + if (devc->input_byte == MPU_ACK) + ok = 1; + else if (input_avail (devc)) + if (uart401_read (devc) == MPU_ACK) + ok = 1; + + restore_flags (flags); +} + +void +attach_uart401 (struct address_info *hw_config) +{ + uart401_devc *devc; + char *name = "MPU-401 (UART) MIDI"; + + if (hw_config->name) + name = hw_config->name; + + if (detected_devc == NULL) + return; + + + devc = (uart401_devc *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (uart401_devc))); + if (sound_nblocks < 1024) + sound_nblocks++;; + if (devc == NULL) + { + printk ("uart401: Can't allocate memory\n"); + return; + } + + memcpy ((char *) devc, (char *) detected_devc, sizeof (uart401_devc)); + detected_devc = NULL; + + devc->irq = hw_config->irq; + if (devc->irq < 0) + { + devc->share_irq = 1; + devc->irq *= -1; + } + else + devc->share_irq = 0; + + if (devc->irq < 1 || devc->irq > 15) + return; + + if (!devc->share_irq) + if (snd_set_irq_handler (devc->irq, uart401intr, "uart401", devc->osp) < 0) + { + printk ("uart401: Failed to allocate IRQ%d\n", devc->irq); + return; + } + + irq2devc[devc->irq] = devc; + devc->my_dev = num_midis; + + request_region (hw_config->io_base, 4, "SB MIDI"); + enter_uart_mode (devc); + + if (num_midis >= MAX_MIDI_DEV) + { + printk ("Sound: Too many midi devices detected\n"); + return; + } + + conf_printf (name, hw_config); + + std_midi_synth.midi_dev = devc->my_dev = num_midis; + + + midi_devs[num_midis] = (struct midi_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct midi_operations))); + + if (sound_nblocks < 1024) + sound_nblocks++;; + if (midi_devs[num_midis] == NULL) + { + printk ("uart401: Failed to allocate memory\n"); + return; + } + + memcpy ((char *) midi_devs[num_midis], (char *) &uart401_operations, + sizeof (struct midi_operations)); + + midi_devs[num_midis]->devc = devc; + + + midi_devs[num_midis]->converter = (struct synth_operations *) (sound_mem_blocks[sound_nblocks] = vmalloc (sizeof (struct synth_operations))); + + if (sound_nblocks < 1024) + sound_nblocks++;; + + if (midi_devs[num_midis]->converter == NULL) + { + printk ("uart401: Failed to allocate memory\n"); + return; + } + + memcpy ((char *) midi_devs[num_midis]->converter, (char *) &std_midi_synth, + sizeof (struct synth_operations)); + + strcpy (midi_devs[num_midis]->info.name, name); + num_midis++; + devc->opened = 0; +} + +static int +reset_uart401 (uart401_devc * devc) +{ + int ok, timeout, n; + + /* + * Send the RESET command. Try again if no success at the first time. + */ + + ok = 0; + + /* save_flags(flags);cli(); */ + + for (n = 0; n < 2 && !ok; n++) + { + for (timeout = 30000; timeout < 0 && !output_ready (devc); timeout--); + + devc->input_byte = 0; + uart401_cmd (devc, MPU_RESET); + + /* + * Wait at least 25 msec. This method is not accurate so let's make the + * loop bit longer. Cannot sleep since this is called during boot. + */ + + for (timeout = 50000; timeout > 0 && !ok; timeout--) + if (devc->input_byte == MPU_ACK) /* Interrupt */ + ok = 1; + else if (input_avail (devc)) + if (uart401_read (devc) == MPU_ACK) + ok = 1; + + } + + if (ok) + uart401_input_loop (devc); /* + * Flush input before enabling interrupts + */ + + /* restore_flags(flags); */ + + return ok; +} + +int +probe_uart401 (struct address_info *hw_config) +{ + int ok = 0; + + static uart401_devc hw_info; + uart401_devc *devc = &hw_info; + + detected_devc = NULL; + + if (check_region (hw_config->io_base, 4)) + return 0; + + devc->base = hw_config->io_base; + devc->irq = hw_config->irq; + devc->osp = hw_config->osp; + devc->midi_input_intr = NULL; + devc->opened = 0; + devc->input_byte = 0; + devc->my_dev = 0; + devc->share_irq = 0; + + ok = reset_uart401 (devc); + + if (ok) + detected_devc = devc; + + return ok; +} + +void +unload_uart401 (struct address_info *hw_config) +{ + uart401_devc *devc; + + int irq = hw_config->irq; + + if (irq < 0) + irq *= -1; + + if (irq < 1 || irq > 15) + return; + + devc = irq2devc[irq]; + if (devc == NULL) + return; + + reset_uart401 (devc); + + release_region (hw_config->io_base, 4); + + if (!devc->share_irq) + snd_release_irq (devc->irq); +} + + +#endif diff -ur --new-file old/linux/drivers/sound/uart6850.c new/linux/drivers/sound/uart6850.c --- old/linux/drivers/sound/uart6850.c Sun Mar 24 21:50:28 1996 +++ new/linux/drivers/sound/uart6850.c Sun Jun 30 10:44:22 1996 @@ -2,27 +2,11 @@ * sound/uart6850.c */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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 @@ -154,7 +138,7 @@ if (uart6850_opened) { printk ("Midi6850: Midi busy\n"); - return -EBUSY; + return -(EBUSY); } ; @@ -238,7 +222,7 @@ static int uart6850_ioctl (int dev, unsigned cmd, caddr_t arg) { - return -EINVAL; + return -(EINVAL); } static void @@ -275,8 +259,8 @@ }; -long -attach_uart6850 (long mem_start, struct address_info *hw_config) +void +attach_uart6850 (struct address_info *hw_config) { int ok, timeout; unsigned long flags; @@ -284,7 +268,7 @@ if (num_midis >= MAX_MIDI_DEV) { printk ("Sound: Too many midi devices detected\n"); - return mem_start; + return; } uart6850_base = hw_config->io_base; @@ -292,7 +276,7 @@ uart6850_irq = hw_config->irq; if (!uart6850_detected) - return -EIO; + return; save_flags (flags); cli (); @@ -310,7 +294,6 @@ std_midi_synth.midi_dev = my_dev = num_midis; midi_devs[num_midis++] = &uart6850_operations; - return mem_start; } static int diff -ur --new-file old/linux/fs/affs/inode.c new/linux/fs/affs/inode.c --- old/linux/fs/affs/inode.c Mon May 20 07:38:40 1996 +++ new/linux/fs/affs/inode.c Thu Jul 25 08:08:28 1996 @@ -44,16 +44,26 @@ lock_super(sb); for (i = 0; i < sb->u.affs_sb.s_bm_count; i++) affs_brelse(sb->u.affs_sb.s_bitmap[i].bm_bh); - ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->bm_flag = htonl(1); - secs_to_datestamp(CURRENT_TIME,&ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->disk_altered); - affs_fix_checksum(sb->s_blocksize,sb->u.affs_sb.s_root_bh->b_data,5); - mark_buffer_dirty(sb->u.affs_sb.s_root_bh,1); + if (!(sb->s_flags & MS_RDONLY)) { + ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->bm_flag = htonl(1); + secs_to_datestamp(CURRENT_TIME, + &ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->disk_altered); + affs_fix_checksum(sb->s_blocksize,sb->u.affs_sb.s_root_bh->b_data,5); + mark_buffer_dirty(sb->u.affs_sb.s_root_bh,1); + } if (sb->u.affs_sb.s_flags & SF_PREFIX) kfree(sb->u.affs_sb.s_prefix); kfree(sb->u.affs_sb.s_bitmap); affs_brelse(sb->u.affs_sb.s_root_bh); + + /* I'm not happy with this. It would be better to save the previous + * value of this devices blksize_size[][] in the super block and + * restore it here, but with the affs superblock being quite large + * already ... + */ set_blocksize(sb->s_dev,BLOCK_SIZE); + sb->s_dev = 0; unlock_super(sb); MOD_DEC_USE_COUNT; @@ -63,13 +73,8 @@ static void affs_write_super(struct super_block *sb) { - int i, clean = 2; + int i, clean = 2; - if ((sb->u.affs_sb.s_flags & SF_USE_MP) && !sb->u.affs_sb.s_uid && sb->s_covered) { - sb->s_mounted->i_uid = sb->u.affs_sb.s_uid = sb->s_covered->i_uid; - sb->s_mounted->i_gid = sb->u.affs_sb.s_gid = sb->s_covered->i_gid; - sb->u.affs_sb.s_flags &= ~SF_USE_MP; - } if (!(sb->s_flags & MS_RDONLY)) { lock_super(sb); for (i = 0, clean = 1; i < sb->u.affs_sb.s_bm_count; i++) { @@ -149,13 +154,6 @@ } *mount_opts |= SF_IMMUTABLE; } - if (!strcmp(this_char,"usemp")) { - if (value) { - printk("AFFS: option usemp does not take an argument\n"); - return 0; - } - *mount_opts |= SF_USE_MP; - } else if (!strcmp(this_char,"verbose")) { if (value) { printk("AFFS: option verbose does not take an argument\n"); @@ -380,6 +378,16 @@ bb = affs_bread(dev,0,s->s_blocksize); if (bb) { chksum = htonl(*(__u32 *)bb->b_data); + + /* Dircache filesystems are compatible with non-dircache ones + * when reading. As long as they aren't supported, writing is + * not recommended. + */ + if ((chksum == FS_DCFFS || chksum == MUFS_DCFFS || chksum == FS_DCOFS + || chksum == MUFS_DCOFS) && !(s->s_flags & MS_RDONLY)) { + printk("AFFS: Dircache FS - mounting %s read only.\n",kdevname(dev)); + s->s_flags |= MS_RDONLY; + } switch (chksum) { case MUFS_FS: case MUFS_INTLFFS: @@ -388,9 +396,11 @@ case FS_INTLFFS: s->u.affs_sb.s_flags |= SF_INTL; break; + case MUFS_DCFFS: case MUFS_FFS: s->u.affs_sb.s_flags |= SF_MUFS; break; + case FS_DCFFS: case FS_FFS: break; case MUFS_OFS: @@ -399,20 +409,13 @@ case FS_OFS: s->u.affs_sb.s_flags |= SF_OFS; break; + case MUFS_DCOFS: case MUFS_INTLOFS: s->u.affs_sb.s_flags |= SF_MUFS; - /* fall thru */ + case FS_DCOFS: case FS_INTLOFS: s->u.affs_sb.s_flags |= SF_INTL | SF_OFS; break; - case FS_DCOFS: - case FS_DCFFS: - case MUFS_DCOFS: - case MUFS_DCFFS: - if (!silent) - printk("AFFS: Unsupported filesystem on device %s: %08X\n", - kdevname(dev),chksum); - if (0) default: printk("AFFS: Unknown filesystem on device %s: %08X\n", kdevname(dev),chksum); @@ -432,8 +435,8 @@ (char *)&chksum,((char *)&chksum)[3] + '0',blocksize); } - s->s_magic = AFFS_SUPER_MAGIC; - s->s_flags = MS_NODEV | MS_NOSUID; + s->s_magic = AFFS_SUPER_MAGIC; + s->s_flags |= MS_NODEV | MS_NOSUID; /* Keep super block in cache */ if (!(s->u.affs_sb.s_root_bh = affs_bread(dev,root_block,s->s_blocksize))) { @@ -587,6 +590,7 @@ affs_brelse(s->u.affs_sb.s_root_bh); if (s->u.affs_sb.s_bitmap) kfree(s->u.affs_sb.s_bitmap); + set_blocksize(dev,BLOCK_SIZE); s->s_dev = 0; unlock_super(s); MOD_DEC_USE_COUNT; @@ -787,7 +791,7 @@ gid = inode->i_gid ^ ~0; } if (!(inode->i_sb->u.affs_sb.s_flags & SF_SETUID)) - file_end->owner_gid = ntohs(uid); + file_end->owner_uid = ntohs(uid); if (!(inode->i_sb->u.affs_sb.s_flags & SF_SETGID)) file_end->owner_gid = ntohs(gid); } diff -ur --new-file old/linux/fs/affs/namei.c new/linux/fs/affs/namei.c --- old/linux/fs/affs/namei.c Sun May 19 14:22:20 1996 +++ new/linux/fs/affs/namei.c Wed Jul 3 11:03:47 1996 @@ -535,7 +535,8 @@ int affs_rename(struct inode *old_dir, const char *old_name, int old_len, - struct inode *new_dir, const char *new_name, int new_len) + struct inode *new_dir, const char *new_name, int new_len, + int must_be_dir) { struct inode *old_inode; struct inode *new_inode; @@ -568,6 +569,8 @@ goto end_rename; old_inode = __iget(old_dir->i_sb,old_ino,0); if (!old_inode) + goto end_rename; + if (must_be_dir && !S_ISDIR(old_inode->i_mode)) goto end_rename; new_bh = affs_find_entry(new_dir,new_name,new_len,&new_ino); if (new_bh) { diff -ur --new-file old/linux/fs/binfmt_aout.c new/linux/fs/binfmt_aout.c --- old/linux/fs/binfmt_aout.c Thu May 16 10:06:34 1996 +++ new/linux/fs/binfmt_aout.c Mon Aug 12 10:10:09 1996 @@ -91,7 +91,7 @@ # define START_DATA(u) (u.u_tsize << PAGE_SHIFT) #endif - if (!current->dumpable) + if (!current->dumpable || current->mm->count != 1) return 0; current->dumpable = 0; diff -ur --new-file old/linux/fs/binfmt_elf.c new/linux/fs/binfmt_elf.c --- old/linux/fs/binfmt_elf.c Sun Apr 14 10:14:43 1996 +++ new/linux/fs/binfmt_elf.c Mon Aug 12 10:09:46 1996 @@ -39,8 +39,21 @@ static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs); static int load_elf_library(int fd); +extern int dump_fpu (struct pt_regs *, elf_fpregset_t *); +extern void dump_thread(struct pt_regs *, struct user *); + +/* + * If we don't support core dumping, then supply a NULL so we + * don't even try. + */ +#ifdef USE_ELF_CORE_DUMP static int elf_core_dump(long signr, struct pt_regs * regs); -extern int dump_fpu (elf_fpregset_t *); +#else +#define elf_core_dump NULL +#endif + +#define ELF_PAGESTART(_v) ((_v) & ~(unsigned long)(ELF_EXEC_PAGESIZE-1)) +#define ELF_PAGEOFFSET(_v) ((_v) & (ELF_EXEC_PAGESIZE-1)) static struct linux_binfmt elf_format = { #ifndef MODULE @@ -90,12 +103,18 @@ } } -unsigned long * create_elf_tables(char * p,int argc,int envc,struct elfhdr * exec, unsigned int load_addr, unsigned int interp_load_addr, int ibcs) +unsigned long * create_elf_tables(char *p, int argc, int envc, + struct elfhdr * exec, + unsigned long load_addr, + unsigned long interp_load_addr, int ibcs) { - unsigned long *argv,*envp, *dlinfo; - unsigned long * sp; + unsigned long *argv, *envp, *dlinfo; + unsigned long *sp; - sp = (unsigned long *) (0xfffffffc & (unsigned long) p); + /* + * Force 16 byte alignment here for generality. + */ + sp = (unsigned long *) (~15UL & (unsigned long) p); sp -= exec ? DLINFO_ITEMS*2 : 2; dlinfo = sp; sp -= envc+1; @@ -110,7 +129,8 @@ #define NEW_AUX_ENT(id, val) \ put_user ((id), dlinfo++); \ put_user ((val), dlinfo++) - if(exec) { /* Put this here for an ELF program interpreter */ + + if (exec) { /* Put this here for an ELF program interpreter */ struct elf_phdr * eppnt; eppnt = (struct elf_phdr *) exec->e_phoff; @@ -128,7 +148,6 @@ } NEW_AUX_ENT (AT_NULL, 0); #undef NEW_AUX_ENT - put_user((unsigned long)argc,--sp); current->mm->arg_start = (unsigned long) p; while (argc-->0) { @@ -152,72 +171,79 @@ is only provided so that we can read a.out libraries that have an ELF header */ -static unsigned int load_elf_interp(struct elfhdr * interp_elf_ex, - struct inode * interpreter_inode, unsigned int *interp_load_addr) +static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, + struct inode * interpreter_inode, + unsigned long *interp_load_addr) { struct file * file; struct elf_phdr *elf_phdata = NULL; struct elf_phdr *eppnt; - unsigned int len; - unsigned int load_addr; + unsigned long load_addr; int elf_exec_fileno; - int elf_bss; int retval; - unsigned int last_bss; - int error; + unsigned long last_bss, elf_bss; + unsigned long error; int i; - unsigned int k; elf_bss = 0; last_bss = 0; error = load_addr = 0; /* First of all, some simple consistency checks */ - if((interp_elf_ex->e_type != ET_EXEC && + if ((interp_elf_ex->e_type != ET_EXEC && interp_elf_ex->e_type != ET_DYN) || - (interp_elf_ex->e_machine != EM_386 && interp_elf_ex->e_machine != EM_486) || + !elf_check_arch(interp_elf_ex->e_machine) || (!interpreter_inode->i_op || !interpreter_inode->i_op->default_file_ops->mmap)){ - return 0xffffffff; + return ~0UL; } /* Now read in all of the header information */ - if(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE) - return 0xffffffff; + if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE) + return ~0UL; elf_phdata = (struct elf_phdr *) - kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, GFP_KERNEL); - if(!elf_phdata) - return 0xffffffff; + kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, + GFP_KERNEL); + if (!elf_phdata) + return ~0UL; /* * If the size of this structure has changed, then punt, since * we will be doing the wrong thing. */ - if( interp_elf_ex->e_phentsize != 32 ) + if (interp_elf_ex->e_phentsize != sizeof(struct elf_phdr)) { kfree(elf_phdata); - return 0xffffffff; + return ~0UL; } - retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff, (char *) elf_phdata, + retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff, + (char *) elf_phdata, sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 1); + if (retval < 0) { + kfree (elf_phdata); + return retval; + } + elf_exec_fileno = open_inode(interpreter_inode, O_RDONLY); if (elf_exec_fileno < 0) { kfree(elf_phdata); - return 0xffffffff; + return ~0UL; } file = current->files->fd[elf_exec_fileno]; eppnt = elf_phdata; for(i=0; ie_phnum; i++, eppnt++) - if(eppnt->p_type == PT_LOAD) { + if (eppnt->p_type == PT_LOAD) { int elf_type = MAP_PRIVATE | MAP_DENYWRITE; int elf_prot = 0; unsigned long vaddr = 0; + unsigned long k; + if (eppnt->p_flags & PF_R) elf_prot = PROT_READ; if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; @@ -227,15 +253,20 @@ } error = do_mmap(file, - load_addr + (vaddr & 0xfffff000), - eppnt->p_filesz + (eppnt->p_vaddr & 0xfff), + load_addr + ELF_PAGESTART(vaddr), + eppnt->p_filesz + ELF_PAGEOFFSET(eppnt->p_vaddr), elf_prot, elf_type, - eppnt->p_offset & 0xfffff000); + ELF_PAGESTART(eppnt->p_offset)); - if(error < 0 && error > -1024) break; /* Real error */ + if (error > -1024UL) { + /* Real error */ + sys_close(elf_exec_fileno); + kfree(elf_phdata); + return ~0UL; + } - if(!load_addr && interp_elf_ex->e_type == ET_DYN) + if (!load_addr && interp_elf_ex->e_type == ET_DYN) load_addr = error; /* @@ -243,23 +274,19 @@ * track of the largest address we see for this. */ k = load_addr + eppnt->p_vaddr + eppnt->p_filesz; - if(k > elf_bss) elf_bss = k; + if (k > elf_bss) elf_bss = k; /* * Do the same thing for the memory mapping - between * elf_bss and last_bss is the bss section. */ k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; - if(k > last_bss) last_bss = k; + if (k > last_bss) last_bss = k; } /* Now use mmap to map the library into memory. */ sys_close(elf_exec_fileno); - if(error < 0 && error > -1024) { - kfree(elf_phdata); - return 0xffffffff; - } /* * Now fill out the bss section. First pad the last page up @@ -268,24 +295,24 @@ * bss page. */ padzero(elf_bss); - len = (elf_bss + 0xfff) & 0xfffff000; /* What we have mapped so far */ + elf_bss = ELF_PAGESTART(elf_bss + ELF_EXEC_PAGESIZE - 1); /* What we have mapped so far */ /* Map the last of the bss segment */ - if (last_bss > len) - do_mmap(NULL, len, last_bss-len, + if (last_bss > elf_bss) + do_mmap(NULL, elf_bss, last_bss-elf_bss, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0); kfree(elf_phdata); *interp_load_addr = load_addr; - return ((unsigned int) interp_elf_ex->e_entry) + load_addr; + return ((unsigned long) interp_elf_ex->e_entry) + load_addr; } -static unsigned int load_aout_interp(struct exec * interp_ex, +static unsigned long load_aout_interp(struct exec * interp_ex, struct inode * interpreter_inode) { int retval; - unsigned int elf_entry; + unsigned long elf_entry; current->mm->brk = interp_ex->a_bss + (current->mm->end_data = interp_ex->a_data + @@ -310,12 +337,12 @@ } else retval = -1; - if(retval >= 0) - do_mmap(NULL, (interp_ex->a_text + interp_ex->a_data + 0xfff) & - 0xfffff000, interp_ex->a_bss, + if (retval >= 0) + do_mmap(NULL, ELF_PAGESTART(interp_ex->a_text + interp_ex->a_data + ELF_EXEC_PAGESIZE - 1), + interp_ex->a_bss, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0); - if(retval < 0) return 0xffffffff; + if (retval < 0) return ~0UL; return elf_entry; } @@ -337,7 +364,7 @@ struct file * file; struct exec interp_ex; struct inode *interpreter_inode; - unsigned int load_addr; + unsigned long load_addr; unsigned int interpreter_type = INTERPRETER_NONE; unsigned char ibcs2_interpreter; int i; @@ -345,13 +372,13 @@ int error; struct elf_phdr * elf_ppnt, *elf_phdata; int elf_exec_fileno; - unsigned int elf_bss, k, elf_brk; + unsigned long elf_bss, k, elf_brk; int retval; char * elf_interpreter; - unsigned int elf_entry, interp_load_addr = 0; + unsigned long elf_entry, interp_load_addr = 0; int status; - unsigned int start_code, end_code, end_data; - unsigned int elf_stack; + unsigned long start_code, end_code, end_data; + unsigned long elf_stack; char passed_fileno[6]; ibcs2_interpreter = 0; @@ -366,9 +393,9 @@ /* First of all, some simple consistency checks */ - if((elf_ex.e_type != ET_EXEC && + if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) || - (elf_ex.e_machine != EM_386 && elf_ex.e_machine != EM_486) || + (! elf_check_arch(elf_ex.e_machine)) || (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops || !bprm->inode->i_op->default_file_ops->mmap)){ return -ENOEXEC; @@ -403,15 +430,15 @@ file = current->files->fd[elf_exec_fileno]; - elf_stack = 0xffffffff; + elf_stack = ~0UL; elf_interpreter = NULL; - start_code = 0xffffffff; + start_code = ~0UL; end_code = 0; end_data = 0; for(i=0;i < elf_ex.e_phnum; i++){ - if(elf_ppnt->p_type == PT_INTERP) { - if( elf_interpreter != NULL ) + if (elf_ppnt->p_type == PT_INTERP) { + if ( elf_interpreter != NULL ) { kfree (elf_phdata); kfree(elf_interpreter); @@ -432,7 +459,8 @@ return -ENOMEM; } - retval = read_exec(bprm->inode,elf_ppnt->p_offset,elf_interpreter, + retval = read_exec(bprm->inode,elf_ppnt->p_offset, + elf_interpreter, elf_ppnt->p_filesz, 1); /* If the program interpreter is one of these two, then assume an iBCS2 image. Otherwise assume @@ -443,22 +471,23 @@ #if 0 printk("Using ELF interpreter %s\n", elf_interpreter); #endif - if(retval >= 0) { + if (retval >= 0) { old_fs = get_fs(); /* This could probably be optimized */ set_fs(get_ds()); - retval = namei(elf_interpreter, &interpreter_inode); + retval = open_namei(elf_interpreter, 0, 0, + &interpreter_inode, NULL); set_fs(old_fs); } - if(retval >= 0) + if (retval >= 0) retval = read_exec(interpreter_inode,0,bprm->buf,128, 1); - if(retval >= 0) { + if (retval >= 0) { interp_ex = *((struct exec *) bprm->buf); /* exec-header */ interp_elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ } - if(retval < 0) { + if (retval < 0) { kfree (elf_phdata); kfree(elf_interpreter); sys_close(elf_exec_fileno); @@ -467,22 +496,22 @@ } elf_ppnt++; } - + /* Some simple consistency checks for the interpreter */ - if(elf_interpreter){ + if (elf_interpreter){ interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT; /* Now figure out which format our binary is */ - if((N_MAGIC(interp_ex) != OMAGIC) && - (N_MAGIC(interp_ex) != ZMAGIC) && - (N_MAGIC(interp_ex) != QMAGIC)) + if ((N_MAGIC(interp_ex) != OMAGIC) && + (N_MAGIC(interp_ex) != ZMAGIC) && + (N_MAGIC(interp_ex) != QMAGIC)) interpreter_type = INTERPRETER_ELF; if (interp_elf_ex.e_ident[0] != 0x7f || strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0) interpreter_type &= ~INTERPRETER_ELF; - if(!interpreter_type) + if (!interpreter_type) { kfree(elf_interpreter); kfree(elf_phdata); @@ -497,17 +526,17 @@ if (!bprm->sh_bang) { char * passed_p; - if(interpreter_type == INTERPRETER_AOUT) { + if (interpreter_type == INTERPRETER_AOUT) { sprintf(passed_fileno, "%d", elf_exec_fileno); passed_p = passed_fileno; - if(elf_interpreter) { + if (elf_interpreter) { bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2); bprm->argc++; } } if (!bprm->p) { - if(elf_interpreter) { + if (elf_interpreter) { kfree(elf_interpreter); } kfree (elf_phdata); @@ -523,7 +552,7 @@ current->mm->end_code = 0; current->mm->start_mmap = ELF_START_MMAP; current->mm->mmap = NULL; - elf_entry = (unsigned int) elf_ex.e_entry; + elf_entry = (unsigned long) elf_ex.e_entry; /* Do this so that we can load the interpreter, if need be. We will change some of these later */ @@ -538,76 +567,69 @@ old_fs = get_fs(); set_fs(get_ds()); - - elf_ppnt = elf_phdata; - for(i=0;i < elf_ex.e_phnum; i++){ - - if(elf_ppnt->p_type == PT_INTERP) { - /* Set these up so that we are able to load the interpreter */ - /* Now load the interpreter into user address space */ - set_fs(old_fs); - - if(interpreter_type & 1) elf_entry = - load_aout_interp(&interp_ex, interpreter_inode); - - if(interpreter_type & 2) elf_entry = - load_elf_interp(&interp_elf_ex, interpreter_inode, &interp_load_addr); - - old_fs = get_fs(); - set_fs(get_ds()); - - iput(interpreter_inode); - kfree(elf_interpreter); - - if(elf_entry == 0xffffffff) { - set_fs(old_fs); - printk("Unable to load interpreter\n"); - kfree(elf_phdata); - send_sig(SIGSEGV, current, 0); - return 0; - } - } - - - if(elf_ppnt->p_type == PT_LOAD) { - int elf_prot = (elf_ppnt->p_flags & PF_R) ? PROT_READ : 0; + for(i = 0, elf_ppnt = elf_phdata; i < elf_ex.e_phnum; i++, elf_ppnt++) { + if (elf_ppnt->p_type == PT_LOAD) { + int elf_prot = 0; + if (elf_ppnt->p_flags & PF_R) elf_prot |= PROT_READ; if (elf_ppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; if (elf_ppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; + error = do_mmap(file, - elf_ppnt->p_vaddr & 0xfffff000, - elf_ppnt->p_filesz + (elf_ppnt->p_vaddr & 0xfff), + ELF_PAGESTART(elf_ppnt->p_vaddr), + (elf_ppnt->p_filesz + + ELF_PAGEOFFSET(elf_ppnt->p_vaddr)), elf_prot, - MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, - elf_ppnt->p_offset & 0xfffff000); + (MAP_FIXED | MAP_PRIVATE | + MAP_DENYWRITE | MAP_EXECUTABLE), + ELF_PAGESTART(elf_ppnt->p_offset)); #ifdef LOW_ELF_STACK - if((elf_ppnt->p_vaddr & 0xfffff000) < elf_stack) - elf_stack = elf_ppnt->p_vaddr & 0xfffff000; + if (ELF_PAGESTART(elf_ppnt->p_vaddr) < elf_stack) + elf_stack = ELF_PAGESTART(elf_ppnt->p_vaddr); #endif - if(!load_addr) + if (!load_addr) load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset; k = elf_ppnt->p_vaddr; - if(k < start_code) start_code = k; + if (k < start_code) start_code = k; k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; - if(k > elf_bss) elf_bss = k; + if (k > elf_bss) elf_bss = k; #if 1 - if((elf_ppnt->p_flags & PF_X) && end_code < k) + if ((elf_ppnt->p_flags & PF_X) && end_code < k) #else - if( !(elf_ppnt->p_flags & PF_W) && end_code < k) + if ( !(elf_ppnt->p_flags & PF_W) && end_code < k) #endif end_code = k; - if(end_data < k) end_data = k; + if (end_data < k) end_data = k; k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; - if(k > elf_brk) elf_brk = k; - } - elf_ppnt++; + if (k > elf_brk) elf_brk = k; + } } set_fs(old_fs); - + + if (elf_interpreter) { + if (interpreter_type & 1) + elf_entry = load_aout_interp(&interp_ex, + interpreter_inode); + else if (interpreter_type & 2) + elf_entry = load_elf_interp(&interp_elf_ex, + interpreter_inode, + &interp_load_addr); + + iput(interpreter_inode); + kfree(elf_interpreter); + + if (elf_entry == ~0UL) { + printk("Unable to load interpreter\n"); + kfree(elf_phdata); + send_sig(SIGSEGV, current, 0); + return 0; + } + } + kfree(elf_phdata); - if(interpreter_type != INTERPRETER_AOUT) sys_close(elf_exec_fileno); + if (interpreter_type != INTERPRETER_AOUT) sys_close(elf_exec_fileno); current->personality = (ibcs2_interpreter ? PER_SVR4 : PER_LINUX); if (current->exec_domain && current->exec_domain->use_count) @@ -639,7 +661,7 @@ load_addr, interp_load_addr, (interpreter_type == INTERPRETER_AOUT ? 0 : 1)); - if(interpreter_type == INTERPRETER_AOUT) + if (interpreter_type == INTERPRETER_AOUT) current->mm->arg_start += strlen(passed_fileno) + 1; current->mm->start_brk = current->mm->brk = elf_brk; current->mm->end_code = end_code; @@ -662,7 +684,7 @@ printk("(brk) %x\n" , current->mm->brk); #endif - if( current->personality == PER_SVR4 ) + if ( current->personality == PER_SVR4 ) { /* Why this, you ask??? Well SVr4 maps page 0 as read-only, and some applications "depend" upon this behavior. @@ -672,14 +694,16 @@ MAP_FIXED | MAP_PRIVATE, 0); } - /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program - starts %edx contains a pointer to a function which might be - registered using `atexit'. This provides a mean for the - dynamic linker to call DT_FINI functions for shared libraries - that have been loaded before the code runs. +#ifdef ELF_PLAT_INIT + /* + * The ABI may specify that certain registers be set up in special + * ways (on i386 %edx is the address of a DT_FINI function, for + * example. This macro performs whatever initialization to + * the regs structure is required. + */ + ELF_PLAT_INIT(regs); +#endif - A value of 0 tells we have no such handler. */ - regs->edx = 0; start_thread(regs, elf_entry, bprm->p); if (current->flags & PF_PTRACED) @@ -707,10 +731,10 @@ struct elfhdr elf_ex; struct elf_phdr *elf_phdata = NULL; struct inode * inode; - unsigned int len; + unsigned long len; int elf_bss; int retval; - unsigned int bss; + unsigned long bss; int error; int i,j, k; @@ -740,14 +764,14 @@ return -ENOEXEC; /* First of all, some simple consistency checks */ - if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 || - (elf_ex.e_machine != EM_386 && elf_ex.e_machine != EM_486) || + if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 || + !elf_check_arch(elf_ex.e_machine) || (!inode->i_op || !inode->i_op->default_file_ops->mmap)) return -ENOEXEC; /* Now read in all of the header information */ - if(sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE) + if (sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE) return -ENOEXEC; elf_phdata = (struct elf_phdr *) @@ -760,9 +784,9 @@ j = 0; for(i=0; ip_type == PT_LOAD) j++; + if ((elf_phdata + i)->p_type == PT_LOAD) j++; - if(j != 1) { + if (j != 1) { kfree(elf_phdata); return -ENOEXEC; } @@ -771,23 +795,23 @@ /* Now use mmap to map the library into memory. */ error = do_mmap(file, - elf_phdata->p_vaddr & 0xfffff000, - elf_phdata->p_filesz + (elf_phdata->p_vaddr & 0xfff), + ELF_PAGESTART(elf_phdata->p_vaddr), + elf_phdata->p_filesz + ELF_PAGEOFFSET(elf_phdata->p_vaddr), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE, - elf_phdata->p_offset & 0xfffff000); + ELF_PAGESTART(elf_phdata->p_offset)); k = elf_phdata->p_vaddr + elf_phdata->p_filesz; - if(k > elf_bss) elf_bss = k; + if (k > elf_bss) elf_bss = k; - if (error != (elf_phdata->p_vaddr & 0xfffff000)) { + if (error != ELF_PAGESTART(elf_phdata->p_vaddr)) { kfree(elf_phdata); return error; } padzero(elf_bss); - len = (elf_phdata->p_filesz + elf_phdata->p_vaddr+ 0xfff) & 0xfffff000; + len = ELF_PAGESTART(elf_phdata->p_filesz + elf_phdata->p_vaddr+ ELF_EXEC_PAGESIZE - 1); bss = elf_phdata->p_memsz + elf_phdata->p_vaddr; if (bss > len) do_mmap(NULL, len, bss-len, @@ -806,7 +830,13 @@ MOD_DEC_USE_COUNT; return retval; } - + +/* + * Note that some platforms still use traditional core dumps and not + * the ELF core dump. Each platform can select it as appropriate. + */ +#ifdef USE_ELF_CORE_DUMP + /* * ELF core dumper * @@ -952,7 +982,7 @@ elf_fpregset_t fpu; /* NT_PRFPREG */ struct elf_prpsinfo psinfo; /* NT_PRPSINFO */ - if (!current->dumpable || limit < PAGE_SIZE) + if (!current->dumpable || limit < PAGE_SIZE || current->mm->count != 1) return 0; current->dumpable = 0; @@ -982,13 +1012,13 @@ /* Set up header */ memcpy(elf.e_ident, ELFMAG, SELFMAG); - elf.e_ident[EI_CLASS] = ELFCLASS32; - elf.e_ident[EI_DATA] = ELFDATA2LSB; + elf.e_ident[EI_CLASS] = ELF_CLASS; + elf.e_ident[EI_DATA] = ELF_DATA; elf.e_ident[EI_VERSION] = EV_CURRENT; memset(elf.e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD); elf.e_type = ET_CORE; - elf.e_machine = EM_386; + elf.e_machine = ELF_ARCH; elf.e_version = EV_CURRENT; elf.e_entry = 0; elf.e_phoff = sizeof(elf); @@ -1062,6 +1092,14 @@ prstatus.pr_cutime.tv_usec = CT_TO_USECS(current->cutime); prstatus.pr_cstime.tv_sec = CT_TO_SECS(current->cstime); prstatus.pr_cstime.tv_usec = CT_TO_USECS(current->cstime); + + /* + * This transfers the registers from regs into the standard + * coredump arrangement, whatever that is. + */ +#ifdef ELF_CORE_COPY_REGS + ELF_CORE_COPY_REGS(prstatus.pr_reg, regs) +#else if (sizeof(elf_gregset_t) != sizeof(struct pt_regs)) { printk("sizeof(elf_gregset_t) (%d) != sizeof(struct pt_regs) (%d)\n", @@ -1069,6 +1107,7 @@ } else *(struct pt_regs *)&prstatus.pr_reg = *regs; +#endif #ifdef DEBUG dump_regs("Passed in regs", (elf_greg_t *)regs); @@ -1110,7 +1149,7 @@ notes[2].data = current; /* Try to dump the fpu. */ - prstatus.pr_fpvalid = dump_fpu (&fpu); + prstatus.pr_fpvalid = dump_fpu (regs, &fpu); if (!prstatus.pr_fpvalid) { numnote--; @@ -1213,14 +1252,17 @@ #endif return has_dumped; } +#endif /* USE_ELF_CORE_DUMP */ -int init_elf_binfmt(void) { +int init_elf_binfmt(void) +{ return register_binfmt(&elf_format); } #ifdef MODULE -int init_module(void) { +int init_module(void) +{ /* Install the COFF, ELF and XOUT loaders. * N.B. We *rely* on the table being the right size with the * right number of free slots... @@ -1229,7 +1271,8 @@ } -void cleanup_module( void) { +void cleanup_module( void) +{ /* Remove the COFF and ELF loaders. */ unregister_binfmt(&elf_format); } diff -ur --new-file old/linux/fs/buffer.c new/linux/fs/buffer.c --- old/linux/fs/buffer.c Tue Jun 4 15:41:44 1996 +++ new/linux/fs/buffer.c Fri Aug 9 15:15:58 1996 @@ -1101,7 +1101,7 @@ if (clear_bit(PG_decr_after, &page->flags)) atomic_dec(&nr_async_pages); if (clear_bit(PG_free_after, &page->flags)) - free_page(page_address(page)); + __free_page(page); if (clear_bit(PG_swap_unlock_after, &page->flags)) swap_after_unlock_page(page->swap_unlock_entry); } @@ -1322,11 +1322,10 @@ */ int generic_readpage(struct inode * inode, struct page * page) { - unsigned long block, address; + unsigned long block; int *p, nr[PAGE_SIZE/512]; int i; - address = page_address(page); page->count++; set_bit(PG_locked, &page->flags); set_bit(PG_free_after, &page->flags); @@ -1342,7 +1341,7 @@ } while (i > 0); /* IO start */ - brw_page(READ, address, inode->i_dev, nr, inode->i_sb->s_blocksize, 1); + brw_page(READ, page_address(page), inode->i_dev, nr, inode->i_sb->s_blocksize, 1); return 0; } diff -ur --new-file old/linux/fs/exec.c new/linux/fs/exec.c --- old/linux/fs/exec.c Wed May 8 17:28:01 1996 +++ new/linux/fs/exec.c Fri Jul 5 14:06:38 1996 @@ -114,41 +114,34 @@ int open_inode(struct inode * inode, int mode) { - int error, fd; - struct file *f, **fpp; + int fd; if (!inode->i_op || !inode->i_op->default_file_ops) return -EINVAL; - f = get_empty_filp(); - if (!f) - return -ENFILE; - fd = 0; - fpp = current->files->fd; - for (;;) { - if (!*fpp) - break; - if (++fd >= NR_OPEN) { - f->f_count--; - return -EMFILE; + fd = get_unused_fd(); + if (fd >= 0) { + struct file * f = get_empty_filp(); + if (!f) { + put_unused_fd(fd); + return -ENFILE; } - fpp++; - } - *fpp = f; - f->f_flags = mode; - f->f_mode = (mode+1) & O_ACCMODE; - f->f_inode = inode; - f->f_pos = 0; - f->f_reada = 0; - f->f_op = inode->i_op->default_file_ops; - if (f->f_op->open) { - error = f->f_op->open(inode,f); - if (error) { - *fpp = NULL; - f->f_count--; - return error; + f->f_flags = mode; + f->f_mode = (mode+1) & O_ACCMODE; + f->f_inode = inode; + f->f_pos = 0; + f->f_reada = 0; + f->f_op = inode->i_op->default_file_ops; + if (f->f_op->open) { + int error = f->f_op->open(inode,f); + if (error) { + f->f_count--; + put_unused_fd(fd); + return error; + } } + current->files->fd[fd] = f; + inode->i_count++; } - inode->i_count++; return fd; } @@ -399,10 +392,45 @@ } /* - * This function flushes out all traces of the currently running executable so - * that a new one can be started + * These functions flushes out all traces of the currently running executable + * so that a new one can be started */ +static inline void flush_old_signals(struct signal_struct *sig) +{ + int i; + struct sigaction * sa = sig->action; + + for (i=32 ; i != 0 ; i--) { + sa->sa_mask = 0; + sa->sa_flags = 0; + if (sa->sa_handler != SIG_IGN) + sa->sa_handler = NULL; + sa++; + } +} + +static inline void flush_old_files(struct files_struct * files) +{ + unsigned long j; + + j = 0; + for (;;) { + unsigned long set, i; + + i = j * __NFDBITS; + if (i >= NR_OPEN) + break; + set = files->close_on_exec.fds_bits[j]; + files->close_on_exec.fds_bits[j] = 0; + j++; + for ( ; set ; i++,set >>= 1) { + if (set & 1) + sys_close(i); + } + } +} + void flush_old_exec(struct linux_binprm * bprm) { int i; @@ -429,17 +457,9 @@ if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || permission(bprm->inode,MAY_READ)) current->dumpable = 0; - current->signal = 0; - for (i=0 ; i<32 ; i++) { - current->sig->action[i].sa_mask = 0; - current->sig->action[i].sa_flags = 0; - if (current->sig->action[i].sa_handler != SIG_IGN) - current->sig->action[i].sa_handler = NULL; - } - for (i=0 ; ifiles->close_on_exec)) - sys_close(i); - FD_ZERO(¤t->files->close_on_exec); + + flush_old_signals(current->sig); + flush_old_files(current->files); } /* diff -ur --new-file old/linux/fs/ext/namei.c new/linux/fs/ext/namei.c --- old/linux/fs/ext/namei.c Mon Sep 18 07:54:10 1995 +++ new/linux/fs/ext/namei.c Wed Jul 3 15:19:00 1996 @@ -885,7 +885,8 @@ * as they are on different partitions. */ int ext_rename(struct inode * old_dir, const char * old_name, int old_len, - struct inode * new_dir, const char * new_name, int new_len) + struct inode * new_dir, const char * new_name, int new_len, + int must_be_dir) { static struct wait_queue * wait = NULL; static int lock = 0; diff -ur --new-file old/linux/fs/ext2/acl.c new/linux/fs/ext2/acl.c --- old/linux/fs/ext2/acl.c Wed Mar 22 09:33:59 1995 +++ new/linux/fs/ext2/acl.c Tue Jul 2 18:08:42 1996 @@ -28,6 +28,13 @@ unsigned short mode = inode->i_mode; /* + * Nobody gets write access to a file on a readonly-fs + */ + if ((mask & S_IWOTH) && + (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) && + IS_RDONLY(inode)) + return -EROFS; + /* * Nobody gets write access to an immutable file */ if ((mask & S_IWOTH) && IS_IMMUTABLE(inode)) diff -ur --new-file old/linux/fs/ext2/ioctl.c new/linux/fs/ext2/ioctl.c --- old/linux/fs/ext2/ioctl.c Sun Jun 2 15:02:50 1996 +++ new/linux/fs/ext2/ioctl.c Tue Jul 2 18:08:42 1996 @@ -82,6 +82,6 @@ inode->i_dirt = 1; return 0; default: - return -EINVAL; + return -ENOTTY; } } diff -ur --new-file old/linux/fs/ext2/namei.c new/linux/fs/ext2/namei.c --- old/linux/fs/ext2/namei.c Mon Dec 11 05:56:35 1995 +++ new/linux/fs/ext2/namei.c Wed Jul 10 12:11:15 1996 @@ -25,12 +25,6 @@ #include /* - * comment out this line if you want names > EXT2_NAME_LEN chars to be - * truncated. Else they will be disallowed. - */ -/* #define NO_TRUNCATE */ - -/* * define how far ahead to read directories while searching them. */ #define NAMEI_RA_CHUNKS 2 @@ -80,13 +74,8 @@ return NULL; sb = dir->i_sb; -#ifdef NO_TRUNCATE if (namelen > EXT2_NAME_LEN) return NULL; -#else - if (namelen > EXT2_NAME_LEN) - namelen = EXT2_NAME_LEN; -#endif memset (bh_use, 0, sizeof (bh_use)); toread = 0; @@ -174,7 +163,11 @@ return -ENOENT; if (!S_ISDIR(dir->i_mode)) { iput (dir); - return -ENOENT; + return -ENOTDIR; + } + if (len > EXT2_NAME_LEN) { + iput (dir); + return -ENAMETOOLONG; } if (dcache_lookup(dir, name, len, &ino)) { if (!ino) { @@ -232,13 +225,13 @@ if (!dir) return NULL; sb = dir->i_sb; -#ifdef NO_TRUNCATE + if (namelen > EXT2_NAME_LEN) + { + *err = -ENAMETOOLONG; return NULL; -#else - if (namelen > EXT2_NAME_LEN) - namelen = EXT2_NAME_LEN; -#endif + } + if (!namelen) return NULL; /* @@ -415,6 +408,11 @@ if (!dir) return -ENOENT; + + if (len > EXT2_NAME_LEN) { + iput (dir); + return -ENAMETOOLONG; + } bh = ext2_find_entry (dir, name, len, &de); if (bh) { brelse (bh); @@ -478,6 +476,10 @@ if (!dir) return -ENOENT; + if (len > EXT2_NAME_LEN) { + iput (dir); + return -ENAMETOOLONG; + } bh = ext2_find_entry (dir, name, len, &de); if (bh) { brelse (bh); @@ -615,6 +617,10 @@ if (!dir) return -ENOENT; inode = NULL; + if (len > EXT2_NAME_LEN) { + iput (dir); + return -ENAMETOOLONG; + } bh = ext2_find_entry (dir, name, len, &de); retval = -ENOENT; if (!bh) @@ -624,8 +630,10 @@ goto end_rmdir; if (inode->i_sb->dq_op) inode->i_sb->dq_op->initialize (inode, -1); - if (inode->i_dev != dir->i_dev) + if (inode->i_dev != dir->i_dev) { + retval = -EBUSY; goto end_rmdir; + } if (de->inode != inode->i_ino) { iput(inode); brelse(bh); @@ -699,6 +707,10 @@ return -ENOENT; retval = -ENOENT; inode = NULL; + if (len > EXT2_NAME_LEN) { + iput (dir); + return -ENAMETOOLONG; + } bh = ext2_find_entry (dir, name, len, &de); if (!bh) goto end_unlink; @@ -928,7 +940,8 @@ */ static int do_ext2_rename (struct inode * old_dir, const char * old_name, int old_len, struct inode * new_dir, - const char * new_name, int new_len) + const char * new_name, int new_len, + int must_be_dir) { struct inode * old_inode, * new_inode; struct buffer_head * old_bh, * new_bh, * dir_bh; @@ -952,6 +965,10 @@ old_inode = new_inode = NULL; old_bh = new_bh = dir_bh = NULL; new_de = NULL; + retval = -ENAMETOOLONG; + if (old_len > EXT2_NAME_LEN) + goto end_rename; + old_bh = ext2_find_entry (old_dir, old_name, old_len, &old_de); retval = -ENOENT; if (!old_bh) @@ -959,6 +976,8 @@ old_inode = __iget (old_dir->i_sb, old_de->inode, 0); /* don't cross mnt-points */ if (!old_inode) goto end_rename; + if (must_be_dir && !S_ISDIR(old_inode->i_mode)) + goto end_rename; retval = -EPERM; if ((old_dir->i_mode & S_ISVTX) && current->fsuid != old_inode->i_uid && @@ -1099,7 +1118,8 @@ * on the same file system */ int ext2_rename (struct inode * old_dir, const char * old_name, int old_len, - struct inode * new_dir, const char * new_name, int new_len) + struct inode * new_dir, const char * new_name, int new_len, + int must_be_dir) { int result; @@ -1107,7 +1127,7 @@ sleep_on (&old_dir->i_sb->u.ext2_sb.s_rename_wait); old_dir->i_sb->u.ext2_sb.s_rename_lock = 1; result = do_ext2_rename (old_dir, old_name, old_len, new_dir, - new_name, new_len); + new_name, new_len, must_be_dir); old_dir->i_sb->u.ext2_sb.s_rename_lock = 0; wake_up (&old_dir->i_sb->u.ext2_sb.s_rename_wait); return result; diff -ur --new-file old/linux/fs/ext2/super.c new/linux/fs/ext2/super.c --- old/linux/fs/ext2/super.c Fri Jun 7 14:45:21 1996 +++ new/linux/fs/ext2/super.c Sun Jul 7 10:06:53 1996 @@ -375,6 +375,7 @@ int db_count; int i, j; + sb->u.ext2_sb.s_mount_opt = 0; set_opt (sb->u.ext2_sb.s_mount_opt, CHECK_NORMAL); if (!parse_options ((char *) data, &sb_block, &resuid, &resgid, &sb->u.ext2_sb.s_mount_opt)) { diff -ur --new-file old/linux/fs/fat/inode.c new/linux/fs/fat/inode.c --- old/linux/fs/fat/inode.c Fri May 10 06:54:52 1996 +++ new/linux/fs/fat/inode.c Sun Aug 4 12:39:07 1996 @@ -23,6 +23,7 @@ #include "tables.h" #include +#include @@ -242,7 +243,8 @@ #define ROUND_TO_MULTIPLE(n,m) ((n) && (m) ? (n)+(m)-1-((n)-1)%(m) : 0) /* don't divide by zero */ - logical_sector_size = CF_LE_W(*(unsigned short *) &b->sector_size); + logical_sector_size = + CF_LE_W(get_unaligned((unsigned short *) &b->sector_size)); sector_mult = logical_sector_size >> SECTOR_BITS; MSDOS_SB(sb)->cluster_size = b->cluster_size*sector_mult; MSDOS_SB(sb)->fats = b->fats; @@ -250,14 +252,16 @@ MSDOS_SB(sb)->fat_length = CF_LE_W(b->fat_length)*sector_mult; MSDOS_SB(sb)->dir_start = (CF_LE_W(b->reserved)+b->fats*CF_LE_W( b->fat_length))*sector_mult; - MSDOS_SB(sb)->dir_entries = CF_LE_W(*((unsigned short *) &b->dir_entries - )); + MSDOS_SB(sb)->dir_entries = + CF_LE_W(get_unaligned((unsigned short *) &b->dir_entries)); MSDOS_SB(sb)->data_start = MSDOS_SB(sb)->dir_start+ROUND_TO_MULTIPLE(( MSDOS_SB(sb)->dir_entries << MSDOS_DIR_BITS) >> SECTOR_BITS, sector_mult); - data_sectors = (CF_LE_W(*((unsigned short *) &b->sectors)) ? - CF_LE_W(*((unsigned short *) &b->sectors)) : - CF_LE_L(b->total_sect))*sector_mult-MSDOS_SB(sb)->data_start; + data_sectors = CF_LE_W(get_unaligned((unsigned short *) &b->sectors)); + if (!data_sectors) { + data_sectors = CF_LE_L(b->total_sect); + } + data_sectors = data_sectors * sector_mult - MSDOS_SB(sb)->data_start; error = !b->cluster_size || !sector_mult; if (!error) { MSDOS_SB(sb)->clusters = b->cluster_size ? data_sectors/ diff -ur --new-file old/linux/fs/fcntl.c new/linux/fs/fcntl.c --- old/linux/fs/fcntl.c Sat May 4 18:39:22 1996 +++ new/linux/fs/fcntl.c Thu Jul 4 20:23:45 1996 @@ -13,23 +13,24 @@ #include #include +#include + extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg); static inline int dupfd(unsigned int fd, unsigned int arg) { - if (fd >= NR_OPEN || !current->files->fd[fd]) + struct files_struct * files = current->files; + + if (fd >= NR_OPEN || !files->fd[fd]) return -EBADF; if (arg >= NR_OPEN) return -EINVAL; - while (arg < NR_OPEN) - if (current->files->fd[arg]) - arg++; - else - break; - if (arg >= NR_OPEN) + arg = find_next_zero_bit(&files->open_fds, NR_OPEN, arg); + if (arg >= current->rlim[RLIMIT_NOFILE].rlim_cur) return -EMFILE; - FD_CLR(arg, ¤t->files->close_on_exec); - (current->files->fd[arg] = current->files->fd[fd])->f_count++; + FD_SET(arg, &files->open_fds); + FD_CLR(arg, &files->close_on_exec); + (files->fd[arg] = files->fd[fd])->f_count++; return arg; } diff -ur --new-file old/linux/fs/file_table.c new/linux/fs/file_table.c --- old/linux/fs/file_table.c Thu Jun 6 12:03:48 1996 +++ new/linux/fs/file_table.c Sat Aug 3 09:43:18 1996 @@ -23,12 +23,16 @@ */ static inline void insert_file_free(struct file *file) { - file->f_count = 0; - file->f_next = first_file; - file->f_prev = first_file->f_prev; - file->f_next->f_prev = file; - file->f_prev->f_next = file; + struct file *next, *prev; + + next = first_file; first_file = file; + file->f_count = 0; + prev = next->f_prev; + file->f_next = next; + next->f_prev = file; + file->f_prev = prev; + prev->f_next = file; } /* @@ -36,11 +40,15 @@ */ static inline void remove_file_free(struct file *file) { - if (first_file == file) - first_file = first_file->f_next; - file->f_next->f_prev = file->f_prev; - file->f_prev->f_next = file->f_next; + struct file *next, *prev; + + next = file->f_next; + prev = file->f_prev; file->f_next = file->f_prev = NULL; + if (first_file == file) + first_file = next; + next->f_prev = prev; + prev->f_next = next; } /* @@ -48,10 +56,14 @@ */ static inline void put_last_free(struct file *file) { - file->f_prev = first_file->f_prev; - file->f_prev->f_next = file; - file->f_next = first_file; - file->f_next->f_prev = file; + struct file *next, *prev; + + next = first_file; + file->f_next = next; + prev = next->f_prev; + next->f_prev = file; + file->f_prev = prev; + prev->f_next = file; } /* diff -ur --new-file old/linux/fs/inode.c new/linux/fs/inode.c --- old/linux/fs/inode.c Mon Jun 3 10:26:47 1996 +++ new/linux/fs/inode.c Wed Jul 24 06:03:07 1996 @@ -476,20 +476,11 @@ return; } -static inline unsigned long value(struct inode * inode) -{ - if (inode->i_lock) - return 1000; - if (inode->i_dirt) - return 1000; - return inode->i_nrpages; -} - struct inode * get_empty_inode(void) { static int ino = 0; struct inode * inode, * best; - unsigned long badness = 1000; + unsigned long badness; int i; if (nr_inodes < max_inodes && nr_free_inodes < (nr_inodes >> 1)) @@ -497,50 +488,54 @@ repeat: inode = first_inode; best = NULL; + badness = 1000; for (i = nr_inodes/2; i > 0; i--,inode = inode->i_next) { if (!inode->i_count) { - unsigned long i = value(inode); + unsigned long i = 999; + if (!(inode->i_lock | inode->i_dirt)) + i = inode->i_nrpages; if (i < badness) { best = inode; - if ((badness = i) == 0) - break; + if (!i) + goto found_good; + badness = i; } } } - if (badness) - if (nr_inodes < max_inodes) { - if (grow_inodes() == 0) - goto repeat; - } - inode = best; - if (!inode) { + if (nr_inodes < max_inodes) { + if (grow_inodes() == 0) + goto repeat; + best = NULL; + } + if (!best) { printk("VFS: No free inodes - contact Linus\n"); sleep_on(&inode_wait); goto repeat; } - if (inode->i_lock) { - wait_on_inode(inode); + if (best->i_lock) { + wait_on_inode(best); goto repeat; } - if (inode->i_dirt) { - write_inode(inode); + if (best->i_dirt) { + write_inode(best); goto repeat; } - if (inode->i_count) + if (best->i_count) goto repeat; - clear_inode(inode); - inode->i_count = 1; - inode->i_nlink = 1; - inode->i_version = ++event; - inode->i_sem.count = 1; - inode->i_ino = ++ino; - inode->i_dev = 0; +found_good: + clear_inode(best); + best->i_count = 1; + best->i_nlink = 1; + best->i_version = ++event; + best->i_sem.count = 1; + best->i_ino = ++ino; + best->i_dev = 0; nr_free_inodes--; if (nr_free_inodes < 0) { printk ("VFS: get_empty_inode: bad free inode count.\n"); nr_free_inodes = 0; } - return inode; + return best; } struct inode * get_pipe_inode(void) diff -ur --new-file old/linux/fs/ioctl.c new/linux/fs/ioctl.c --- old/linux/fs/ioctl.c Sun Mar 10 08:28:56 1996 +++ new/linux/fs/ioctl.c Tue Jul 2 18:08:42 1996 @@ -51,7 +51,7 @@ } if (filp->f_op && filp->f_op->ioctl) return filp->f_op->ioctl(filp->f_inode, filp, cmd, arg); - return -EINVAL; + return -ENOTTY; } @@ -103,6 +103,6 @@ if (filp->f_op && filp->f_op->ioctl) return filp->f_op->ioctl(filp->f_inode, filp, cmd, arg); - return -EINVAL; + return -ENOTTY; } } diff -ur --new-file old/linux/fs/isofs/dir.c new/linux/fs/isofs/dir.c --- old/linux/fs/isofs/dir.c Fri Dec 22 12:00:19 1995 +++ new/linux/fs/isofs/dir.c Tue Jul 23 09:26:40 1996 @@ -5,9 +5,11 @@ * * (C) 1991 Linus Torvalds - minix filesystem * + * Steve Beynon : Missing last directory entries fixed + * (stephen@askone.demon.co.uk) : 21st June 1996 + * * isofs directory handling functions */ - #include #include #include @@ -133,9 +135,13 @@ #ifdef DEBUG printk("Block, offset, f_pos: %x %x %x\n", block, offset, filp->f_pos); + printk("inode->i_size = %x\n",inode->i_size); #endif /* Next directory_record on next CDROM sector */ if (offset >= bufsize) { +#ifdef DEBUG + printk("offset >= bufsize\n"); +#endif brelse(bh); offset = 0; block = isofs_bmap(inode, (filp->f_pos) >> bufbits); @@ -151,6 +157,10 @@ inode_number = (block << bufbits) + (offset & (bufsize - 1)); de_len = *(unsigned char *) de; +#ifdef DEBUG + printk("de_len = %ld\n", de_len); +#endif + /* If the length byte is zero, we should move on to the next CDROM sector. If we are at the end of the directory, we @@ -175,15 +185,31 @@ If not, put the two halves together in "tmpde" */ next_offset = offset + de_len; if (next_offset > bufsize) { +#ifdef DEBUG + printk("next_offset (%x) > bufsize (%x)\n",next_offset,bufsize); +#endif next_offset &= (bufsize - 1); - memcpy(tmpde, de, bufsize - offset); + memcpy(tmpde, de, bufsize - offset); brelse(bh); block = isofs_bmap(inode, (filp->f_pos + de_len) >> bufbits); if (!block) + { return 0; - bh = breada(inode->i_dev, block, bufsize, filp->f_pos+de_len, inode->i_size); + } + + bh = breada(inode->i_dev, block, bufsize, + filp->f_pos, + inode->i_size); if (!bh) + { +#ifdef DEBUG + printk("!bh block=%ld, bufsize=%ld\n",block,bufsize); + printk("filp->f_pos = %ld\n",filp->f_pos); + printk("inode->i_size = %ld\n", inode->i_size); +#endif return 0; + } + memcpy(bufsize - offset + (char *) tmpde, bh->b_data, next_offset); de = tmpde; } diff -ur --new-file old/linux/fs/isofs/inode.c new/linux/fs/isofs/inode.c --- old/linux/fs/isofs/inode.c Fri May 31 12:46:26 1996 +++ new/linux/fs/isofs/inode.c Mon Aug 12 12:44:47 1996 @@ -25,7 +25,12 @@ #include #include -#define MULTI_VOLUME +/* + * We have no support for "multi volume" CDs, but more and more disks carry + * wrong information within the volume descriptors. + */ +#define IGNORE_WRONG_MULTI_VOLUME_SPECS + #ifdef LEAK_CHECK static int check_malloc = 0; static int check_bread = 0; @@ -161,7 +166,22 @@ /* * look if the driver can tell the multi session redirection value + * + * don't change this if you don't know what you do, please! + * Multisession is legal only with XA disks. + * A non-XA disk with more than one volume descriptor may do it right, but + * usually is written in a nowhere standardized "multi-partition" manner. + * Multisession uses absolute addressing (solely the first frame of the whole + * track is #0), multi-partition uses relative addressing (each first frame of + * each track is #0), and a track is not a session. + * + * A broken CDwriter software or drive firmware does not set new standards, + * at least not if conflicting with the existing ones. + * + * emoenke@gwdg.de */ +#define WE_OBEY_THE_WRITTEN_STANDARDS 1 + static unsigned int isofs_get_last_session(kdev_t dev) { struct cdrom_multisession ms_info; @@ -189,7 +209,11 @@ printk("isofs.inode: vol_desc_start = %d\n", ms_info.addr.lba); } #endif 0 - if ((i==0)&&(ms_info.xa_flag)) vol_desc_start=ms_info.addr.lba; + if (i==0) +#if WE_OBEY_THE_WRITTEN_STANDARDS + if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */ +#endif WE_OBEY_THE_WRITTEN_STANDARDS + vol_desc_start=ms_info.addr.lba; } return vol_desc_start; } @@ -305,23 +329,23 @@ if(high_sierra){ rootp = (struct iso_directory_record *) h_pri->root_directory_record; +#ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS if (isonum_723 (h_pri->volume_set_size) != 1) { -#ifndef MULTI_VOLUME - printk("Multi-volume disks not (yet) supported.\n"); + printk("Multi-volume disks not supported.\n"); goto out; -#endif } +#endif IGNORE_WRONG_MULTI_VOLUME_SPECS s->u.isofs_sb.s_nzones = isonum_733 (h_pri->volume_space_size); s->u.isofs_sb.s_log_zone_size = isonum_723 (h_pri->logical_block_size); s->u.isofs_sb.s_max_size = isonum_733(h_pri->volume_space_size); } else { rootp = (struct iso_directory_record *) pri->root_directory_record; +#ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS if (isonum_723 (pri->volume_set_size) != 1) { -#ifndef MULTI_VOLUME - printk("Multi-volume disks not (yet) supported.\n"); + printk("Multi-volume disks not supported.\n"); goto out; -#endif } +#endif IGNORE_WRONG_MULTI_VOLUME_SPECS s->u.isofs_sb.s_nzones = isonum_733 (pri->volume_space_size); s->u.isofs_sb.s_log_zone_size = isonum_723 (pri->logical_block_size); s->u.isofs_sb.s_max_size = isonum_733(pri->volume_space_size); @@ -628,16 +652,16 @@ */ if (inode->i_sb->u.isofs_sb.s_cruft == 'n' && (volume_seq_no != 0) && (volume_seq_no != 1)) { - printk("Warning: defective cdrom. Enabling \"cruft\" mount option.\n"); + printk("Warning: defective cdrom (volume sequence number). Enabling \"cruft\" mount option.\n"); inode->i_sb->u.isofs_sb.s_cruft = 'y'; } -#ifndef MULTI_VOLUME +#ifndef IGNORE_WRONG_MULTI_VOLUME_SPECS if (inode->i_sb->u.isofs_sb.s_cruft != 'y' && (volume_seq_no != 0) && (volume_seq_no != 1)) { printk("Multi volume CD somehow got mounted.\n"); } else -#endif +#endif IGNORE_WRONG_MULTI_VOLUME_SPECS { if (S_ISREG(inode->i_mode)) inode->i_op = &isofs_file_inode_operations; diff -ur --new-file old/linux/fs/locks.c new/linux/fs/locks.c --- old/linux/fs/locks.c Sat Jun 8 15:50:57 1996 +++ new/linux/fs/locks.c Tue Jul 2 18:08:42 1996 @@ -317,6 +317,8 @@ break; case F_UNLCK : break; + default: + return -EINVAL; } return (posix_lock_file(filp, &file_lock, cmd == F_SETLKW)); @@ -448,7 +450,7 @@ if (current->signal & ~current->blocked) return (-ERESTARTSYS); if (posix_locks_deadlock(current, fl->fl_owner)) - return (-EDEADLOCK); + return (-EDEADLK); interruptible_sleep_on(&fl->fl_wait); if (current->signal & ~current->blocked) return (-ERESTARTSYS); @@ -762,7 +764,7 @@ if (current->signal & ~current->blocked) return (-ERESTARTSYS); if (posix_locks_deadlock(caller->fl_owner, fl->fl_owner)) - return (-EDEADLOCK); + return (-EDEADLK); interruptible_sleep_on(&fl->fl_wait); if (current->signal & ~current->blocked) return (-ERESTARTSYS); diff -ur --new-file old/linux/fs/minix/namei.c new/linux/fs/minix/namei.c --- old/linux/fs/minix/namei.c Wed Nov 8 11:22:48 1995 +++ new/linux/fs/minix/namei.c Wed Jul 3 12:13:21 1996 @@ -672,7 +672,7 @@ * higher-level routines. */ static int do_minix_rename(struct inode * old_dir, const char * old_name, int old_len, - struct inode * new_dir, const char * new_name, int new_len) + struct inode * new_dir, const char * new_name, int new_len, int must_be_dir) { struct inode * old_inode, * new_inode; struct buffer_head * old_bh, * new_bh, * dir_bh; @@ -700,6 +700,8 @@ old_inode = __iget(old_dir->i_sb, old_de->inode,0); /* don't cross mnt-points */ if (!old_inode) goto end_rename; + if (must_be_dir && !S_ISDIR(old_inode->i_mode)) + goto end_rename; retval = -EPERM; if ((old_dir->i_mode & S_ISVTX) && current->fsuid != old_inode->i_uid && @@ -816,7 +818,8 @@ * as they are on different partitions. */ int minix_rename(struct inode * old_dir, const char * old_name, int old_len, - struct inode * new_dir, const char * new_name, int new_len) + struct inode * new_dir, const char * new_name, int new_len, + int must_be_dir) { static struct wait_queue * wait = NULL; static int lock = 0; @@ -826,7 +829,7 @@ sleep_on(&wait); lock = 1; result = do_minix_rename(old_dir, old_name, old_len, - new_dir, new_name, new_len); + new_dir, new_name, new_len, must_be_dir); lock = 0; wake_up(&wait); return result; diff -ur --new-file old/linux/fs/msdos/namei.c new/linux/fs/msdos/namei.c --- old/linux/fs/msdos/namei.c Fri May 10 06:54:52 1996 +++ new/linux/fs/msdos/namei.c Wed Jul 3 11:08:03 1996 @@ -738,7 +738,8 @@ /***** Rename, a wrapper for rename_same_dir & rename_diff_dir */ int msdos_rename(struct inode *old_dir,const char *old_name,int old_len, - struct inode *new_dir,const char *new_name,int new_len) + struct inode *new_dir,const char *new_name,int new_len, + int must_be_dir) { struct super_block *sb = old_dir->i_sb; char old_msdos_name[MSDOS_NAME],new_msdos_name[MSDOS_NAME]; diff -ur --new-file old/linux/fs/namei.c new/linux/fs/namei.c --- old/linux/fs/namei.c Tue Apr 16 09:27:10 1996 +++ new/linux/fs/namei.c Sun Jul 7 19:27:04 1996 @@ -102,6 +102,9 @@ if (inode->i_op && inode->i_op->permission) return inode->i_op->permission(inode, mask); + else if ((mask & S_IWOTH) && IS_RDONLY(inode) && + (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) + return -EROFS; /* Nobody gets write access to a read-only fs */ else if ((mask & S_IWOTH) && IS_IMMUTABLE(inode)) return -EACCES; /* Nobody gets write access to an immutable file */ else if (current->fsuid == inode->i_uid) @@ -363,12 +366,12 @@ iput(inode); error = -EEXIST; } - } else if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) - ; /* error is already set! */ + } else if (IS_RDONLY(dir)) + error = -EROFS; else if (!dir->i_op || !dir->i_op->create) error = -EACCES; - else if (IS_RDONLY(dir)) - error = -EROFS; + else if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) + ; /* error is already set! */ else { dir->i_count++; /* create eats the dir */ if (dir->i_sb && dir->i_sb->dq_op) @@ -405,6 +408,7 @@ * If there was something like IS_NODEV(inode) for * pipes and/or sockets I'd check it here. */ + flag &= ~O_TRUNC; } else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) { if (IS_NODEV(inode)) { @@ -515,6 +519,43 @@ return error; } +/* + * Some operations need to remove trailing slashes for POSIX.1 + * conformance. For rename we also need to change the behaviour + * depending on whether we had a trailing slash or not.. (we + * cannot rename normal files with trailing slashes, only dirs) + * + * "dummy" is used to make sure we don't do "/" -> "". + */ +static int remove_trailing_slashes(char * name) +{ + int result; + char dummy[1]; + char *remove = dummy+1; + + for (;;) { + char c = *name; + name++; + if (!c) + break; + if (c != '/') { + remove = NULL; + continue; + } + if (remove) + continue; + remove = name; + } + + result = 0; + if (remove) { + remove[-1] = 0; + result = 1; + } + + return result; +} + static int do_mkdir(const char * pathname, int mode) { const char * basename; @@ -557,6 +598,7 @@ error = getname(pathname,&tmp); if (!error) { + remove_trailing_slashes(tmp); error = do_mkdir(tmp,mode); putname(tmp); } @@ -607,6 +649,7 @@ error = getname(pathname,&tmp); if (!error) { + remove_trailing_slashes(tmp); error = do_rmdir(tmp); putname(tmp); } @@ -788,7 +831,7 @@ return error; } -static int do_rename(const char * oldname, const char * newname) +static int do_rename(const char * oldname, const char * newname, int must_be_dir) { struct inode * old_dir, * new_dir; const char * old_base, * new_base; @@ -852,7 +895,7 @@ new_dir->i_sb->dq_op->initialize(new_dir, -1); down(&new_dir->i_sem); error = old_dir->i_op->rename(old_dir, old_base, old_len, - new_dir, new_base, new_len); + new_dir, new_base, new_len, must_be_dir); up(&new_dir->i_sem); iput(new_dir); return error; @@ -867,7 +910,9 @@ if (!error) { error = getname(newname,&to); if (!error) { - error = do_rename(from,to); + error = do_rename(from,to, + remove_trailing_slashes(from) | + remove_trailing_slashes(to)); putname(to); } putname(from); diff -ur --new-file old/linux/fs/ncpfs/dir.c new/linux/fs/ncpfs/dir.c --- old/linux/fs/ncpfs/dir.c Sun Jun 2 10:21:10 1996 +++ new/linux/fs/ncpfs/dir.c Thu Jul 18 14:52:00 1996 @@ -63,7 +63,8 @@ static int ncp_rename(struct inode *old_dir, const char *old_name, int old_len, - struct inode *new_dir, const char *new_name, int new_len); + struct inode *new_dir, const char *new_name, int new_len, + int must_be_dir); static inline void str_upper(char *name) @@ -91,6 +92,20 @@ } } +static inline int +ncp_namespace(struct inode *i) +{ + struct ncp_server *server = NCP_SERVER(i); + struct nw_info_struct *info = NCP_ISTRUCT(i); + return server->name_space[info->volNumber]; +} + +static inline int +ncp_preserve_case(struct inode *i) +{ + return (ncp_namespace(i) == NW_NS_OS2); +} + static struct file_operations ncp_dir_operations = { NULL, /* lseek - default */ ncp_dir_read, /* read - bad */ @@ -127,7 +142,7 @@ /* Here we encapsulate the inode number handling that depends upon the * mount mode: When we mount a complete server, the memory address of * the ncp_inode_info is used as the inode number. When only a single - * volume is mounted, then the DosDirNum is used as the inode + * volume is mounted, then the dirEntNum is used as the inode * number. As this is unique for the complete volume, this should * enable the NFS exportability of a ncpfs-mounted volume. */ @@ -142,7 +157,7 @@ ncp_info_ino(struct ncp_server *server, struct ncp_inode_info *info) { return ncp_single_volume(server) - ? info->finfo.i.DosDirNum : (ino_t)info; + ? info->finfo.i.dirEntNum : (ino_t)info; } static inline int @@ -176,8 +191,6 @@ return NULL; } - - static int ncp_dir_read(struct inode *inode, struct file *filp, char *buf, int count) { @@ -325,9 +338,12 @@ c_last_returned_index = 0; index = 0; - for (i = 0; i < c_size; i++) + if (!ncp_preserve_case(inode)) { - str_lower(c_entry[i].i.entryName); + for (i = 0; i < c_size; i++) + { + str_lower(c_entry[i].i.entryName); + } } } } @@ -344,7 +360,7 @@ if (ncp_single_volume(server)) { - ino = (ino_t)(entry->i.DosDirNum); + ino = (ino_t)(entry->i.dirEntNum); } else { @@ -651,7 +667,7 @@ root->finfo.opened = 0; i->attributes = aDIR; i->dataStreamSize = 1024; - i->DosDirNum = 0; + i->dirEntNum = i->DosDirNum = 0; i->volNumber = NCP_NUMBER_OF_VOLUMES+1; /* illegal volnum */ ncp_date_unix2dos(0, &(i->creationTime), &(i->creationDate)); ncp_date_unix2dos(0, &(i->modifyTime), &(i->modifyDate)); @@ -728,7 +744,7 @@ do { - if ( (result->dir->finfo.i.DosDirNum == dir_info->DosDirNum) + if ( (result->dir->finfo.i.dirEntNum == dir_info->dirEntNum) && (result->dir->finfo.i.volNumber == dir_info->volNumber) && (strcmp(result->finfo.i.entryName, name) == 0) /* The root dir is never looked up using this @@ -756,6 +772,7 @@ struct ncp_server *server; struct ncp_inode_info *result_info; int found_in_cache; + int down_case = 0; char name[len+1]; *result = NULL; @@ -866,20 +883,26 @@ if (found_in_cache == 0) { int res; - str_upper(name); DDPRINTK("ncp_lookup: do_lookup on %s/%s\n", NCP_ISTRUCT(dir)->entryName, name); if (ncp_is_server_root(dir)) { + str_upper(name); + down_case = 1; res = ncp_lookup_volume(server, name, &(finfo.i)); } else { + if (!ncp_preserve_case(dir)) + { + str_upper(name); + down_case = 1; + } res = ncp_obtain_info(server, NCP_ISTRUCT(dir)->volNumber, - NCP_ISTRUCT(dir)->DosDirNum, + NCP_ISTRUCT(dir)->dirEntNum, name, &(finfo.i)); } if (res != 0) @@ -891,7 +914,11 @@ } finfo.opened = 0; - str_lower(finfo.i.entryName); + + if (down_case != 0) + { + str_lower(finfo.i.entryName); + } if (!(*result = ncp_iget(dir, &finfo))) { @@ -928,7 +955,11 @@ strncpy(_name, name, len); _name[len] = '\0'; - str_upper(_name); + + if (!ncp_preserve_case(dir)) + { + str_upper(_name); + } lock_super(dir->i_sb); if (ncp_open_create_file_or_subdir(NCP_SERVER(dir), @@ -945,7 +976,11 @@ ncp_invalid_dir_cache(dir); - str_lower(finfo.i.entryName); + if (!ncp_preserve_case(dir)) + { + str_lower(finfo.i.entryName); + } + finfo.access = O_RDWR; if (!(*result = ncp_iget(dir, &finfo)) < 0) @@ -979,7 +1014,11 @@ strncpy(_name, name, len); _name[len] = '\0'; - str_upper(_name); + + if (!ncp_preserve_case(dir)) + { + str_upper(_name); + } if (!dir || !S_ISDIR(dir->i_mode)) { @@ -1037,7 +1076,11 @@ strncpy(_name, name, len); _name[len] = '\0'; - str_upper(_name); + + if (!ncp_preserve_case(dir)) + { + str_upper(_name); + } if ((error = ncp_del_file_or_subdir(NCP_SERVER(dir), NCP_ISTRUCT(dir), @@ -1080,7 +1123,11 @@ { strncpy(_name, name, len); _name[len] = '\0'; - str_upper(_name); + + if (!ncp_preserve_case(dir)) + { + str_upper(_name); + } if ((error = ncp_del_file_or_subdir(NCP_SERVER(dir), NCP_ISTRUCT(dir), @@ -1099,7 +1146,8 @@ static int ncp_rename(struct inode *old_dir, const char *old_name, int old_len, - struct inode *new_dir, const char *new_name, int new_len) + struct inode *new_dir, const char *new_name, int new_len, + int must_be_dir) { int res; char _old_name[old_len+1]; @@ -1134,11 +1182,19 @@ strncpy(_old_name, old_name, old_len); _old_name[old_len] = '\0'; - str_upper(_old_name); + + if (!ncp_preserve_case(old_dir)) + { + str_upper(_old_name); + } strncpy(_new_name, new_name, new_len); _new_name[new_len] = '\0'; - str_upper(_new_name); + + if (!ncp_preserve_case(new_dir)) + { + str_upper(_new_name); + } res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir), NCP_ISTRUCT(old_dir), _old_name, diff -ur --new-file old/linux/fs/ncpfs/ncplib_kernel.c new/linux/fs/ncpfs/ncplib_kernel.c --- old/linux/fs/ncpfs/ncplib_kernel.c Fri Mar 22 11:58:41 1996 +++ new/linux/fs/ncpfs/ncplib_kernel.c Thu Jul 18 14:52:00 1996 @@ -190,25 +190,6 @@ } int -ncp_get_volume_number(struct ncp_server *server, const char *name, int *target) -{ - int result; - - ncp_init_request_s(server, 5); - ncp_add_pstring(server, name); - - if ((result = ncp_request(server, 22)) != 0) - { - ncp_unlock_server(server); - return result; - } - - *target = ncp_reply_byte(server, 0); - ncp_unlock_server(server); - return 0; -} - -int ncp_close_file(struct ncp_server *server, const char *file_id) { int result; @@ -278,8 +259,8 @@ ncp_init_request(server); ncp_add_byte(server, 6); /* subfunction */ - ncp_add_byte(server, 0); /* dos name space */ - ncp_add_byte(server, 0); /* dos name space as dest */ + ncp_add_byte(server, server->name_space[vol_num]); + ncp_add_byte(server, server->name_space[vol_num]); ncp_add_word(server, 0xff); /* get all */ ncp_add_dword(server, RIM_ALL); ncp_add_handle_path(server, vol_num, dir_base, 1, path); @@ -295,20 +276,57 @@ return 0; } +static inline int +ncp_has_os2_namespace(struct ncp_server *server, __u8 volume) +{ + int result; + __u8 *namespace; + __u16 no_namespaces; + + ncp_init_request(server); + ncp_add_byte(server, 24); /* Subfunction: Get Name Spaces Loaded */ + ncp_add_word(server, 0); + ncp_add_byte(server, volume); + + if ((result = ncp_request(server, 87)) != 0) + { + ncp_unlock_server(server); + return 0; + } + + no_namespaces = ncp_reply_word(server, 0); + namespace = ncp_reply_data(server, 2); + + while (no_namespaces > 0) + { + DPRINTK("get_namespaces: found %d on %d\n", *namespace,volume); + + if (*namespace == 4) + { + DPRINTK("get_namespaces: found OS2\n"); + ncp_unlock_server(server); + return 1; + } + namespace += 1; + no_namespaces -= 1; + } + ncp_unlock_server(server); + return 0; +} + int ncp_lookup_volume(struct ncp_server *server, char *volname, struct nw_info_struct *target) { int result; - __u8 vol_num; - __u32 dir_base; + int volnum; DPRINTK("ncp_lookup_volume: looking up vol %s\n", volname); ncp_init_request(server); ncp_add_byte(server, 22); /* Subfunction: Generate dir handle */ - ncp_add_byte(server, 0); /* DOS name space */ + ncp_add_byte(server, 0); /* DOS namespace */ ncp_add_byte(server, 0); /* reserved */ ncp_add_byte(server, 0); /* reserved */ ncp_add_byte(server, 0); /* reserved */ @@ -325,20 +343,19 @@ return result; } - dir_base = ncp_reply_dword(server, 4); - vol_num = ncp_reply_byte(server, 8); + memset(target, 0, sizeof(*target)); + target->DosDirNum = target->dirEntNum = ncp_reply_dword(server, 4); + target->volNumber = volnum = ncp_reply_byte(server, 8); ncp_unlock_server(server); - if ((result = ncp_obtain_info(server, vol_num, dir_base, NULL, - target)) != 0) - { - return result; - } + server->name_space[volnum] = ncp_has_os2_namespace(server,volnum)?4:0; - DPRINTK("ncp_lookup_volume: attribs = %X\n", target->attributes); + DPRINTK("lookup_vol: namespace[%d] = %d\n", + volnum, server->name_space[volnum]); target->nameLen = strlen(volname); strcpy(target->entryName, volname); + target->attributes = aDIR; return 0; } @@ -352,14 +369,14 @@ ncp_init_request(server); ncp_add_byte(server, 7); /* subfunction */ - ncp_add_byte(server, 0); /* dos name space */ + ncp_add_byte(server, server->name_space[file->volNumber]); ncp_add_byte(server, 0); /* reserved */ ncp_add_word(server, 0x8006); /* search attribs: all */ ncp_add_dword(server, info_mask); ncp_add_mem(server, info, sizeof(*info)); ncp_add_handle_path(server, file->volNumber, - file->DosDirNum, 1, NULL); + file->dirEntNum, 1, NULL); result = ncp_request(server, 87); ncp_unlock_server(server); @@ -374,11 +391,11 @@ ncp_init_request(server); ncp_add_byte(server, 8); /* subfunction */ - ncp_add_byte(server, 0); /* dos name space */ + ncp_add_byte(server, server->name_space[dir->volNumber]); ncp_add_byte(server, 0); /* reserved */ ncp_add_word(server, 0x8006); /* search attribs: all */ ncp_add_handle_path(server, dir->volNumber, - dir->DosDirNum, 1, name); + dir->dirEntNum, 1, name); result = ncp_request(server, 87); ncp_unlock_server(server); @@ -406,15 +423,16 @@ { int result; __u16 search_attribs = 0x0006; + __u8 volume = (dir != NULL) ? dir->volNumber : target->i.volNumber; if ((create_attributes & aDIR) != 0) { - search_attribs |= 0x8000; - } + search_attribs |= 0x8000; +} ncp_init_request(server); ncp_add_byte(server, 1); /* subfunction */ - ncp_add_byte(server, 0); /* dos name space */ + ncp_add_byte(server, server->name_space[volume]); ncp_add_byte(server, open_create_mode); ncp_add_word(server, search_attribs); ncp_add_dword(server, RIM_ALL); @@ -425,13 +443,11 @@ if (dir != NULL) { - ncp_add_handle_path(server, dir->volNumber, - dir->DosDirNum, 1, name); + ncp_add_handle_path(server, volume, dir->dirEntNum, 1, name); } else { - ncp_add_handle_path(server, - target->i.volNumber, target->i.DosDirNum, + ncp_add_handle_path(server, volume, target->i.dirEntNum, 1, NULL); } @@ -467,9 +483,9 @@ ncp_init_request(server); ncp_add_byte(server, 2); /* subfunction */ - ncp_add_byte(server, 0); /* dos name space */ + ncp_add_byte(server, server->name_space[dir->volNumber]); ncp_add_byte(server, 0); /* reserved */ - ncp_add_handle_path(server, dir->volNumber, dir->DosDirNum, 1, NULL); + ncp_add_handle_path(server, dir->volNumber, dir->dirEntNum, 1, NULL); if ((result = ncp_request(server, 87)) != 0) { @@ -493,7 +509,7 @@ ncp_init_request(server); ncp_add_byte(server, 3); /* subfunction */ - ncp_add_byte(server, 0); /* dos name space */ + ncp_add_byte(server, server->name_space[seq->volNumber]); ncp_add_byte(server, 0); /* data stream (???) */ ncp_add_word(server, 0xffff); /* Search attribs */ ncp_add_dword(server, RIM_ALL); /* return info mask */ @@ -528,19 +544,19 @@ ncp_init_request(server); ncp_add_byte(server, 4); /* subfunction */ - ncp_add_byte(server, 0); /* dos name space */ + ncp_add_byte(server, server->name_space[old_dir->volNumber]); ncp_add_byte(server, 1); /* rename flag */ ncp_add_word(server, 0x8006); /* search attributes */ /* source Handle Path */ ncp_add_byte(server, old_dir->volNumber); - ncp_add_dword(server, old_dir->DosDirNum); + ncp_add_dword(server, old_dir->dirEntNum); ncp_add_byte(server, 1); ncp_add_byte(server, 1); /* 1 source component */ /* dest Handle Path */ ncp_add_byte(server, new_dir->volNumber); - ncp_add_dword(server, new_dir->DosDirNum); + ncp_add_dword(server, new_dir->dirEntNum); ncp_add_byte(server, 1); ncp_add_byte(server, 1); /* 1 destination component */ diff -ur --new-file old/linux/fs/ncpfs/sock.c new/linux/fs/ncpfs/sock.c --- old/linux/fs/ncpfs/sock.c Thu May 16 15:35:42 1996 +++ new/linux/fs/ncpfs/sock.c Wed Jul 10 12:19:24 1996 @@ -599,7 +599,7 @@ if (server->has_subfunction != 0) { - *(__u16 *)&(h->data[0]) = request_size - 2; + *(__u16 *)&(h->data[0]) = htons(request_size - 2); } h->type = NCP_REQUEST; diff -ur --new-file old/linux/fs/nfs/bio.c new/linux/fs/nfs/bio.c --- old/linux/fs/nfs/bio.c Sun Jun 9 10:21:12 1996 +++ new/linux/fs/nfs/bio.c Sat Jun 29 11:00:46 1996 @@ -16,6 +16,9 @@ * Another possible solution to this problem may be to have a cache of recent * RPC call results indexed by page pointer, or even a result code field * in struct page. + * + * June 96: Added retries of RPCs that seem to have failed for a transient + * reason. */ #include @@ -90,64 +93,114 @@ } /* + * This is the function to (re-) transmit an NFS readahead request + */ +static int +nfsiod_read_setup(struct nfsiod_req *req) +{ + struct inode *inode = req->rq_inode; + struct page *page = req->rq_page; + + return nfs_proc_read_request(&req->rq_rpcreq, + NFS_SERVER(inode), NFS_FH(inode), + page->offset, PAGE_SIZE, + (__u32 *) page_address(page)); +} + +/* * This is the callback from nfsiod telling us whether a reply was * received or some error occurred (timeout or socket shutdown). */ -static void -nfs_read_cb(int result, struct nfsiod_req *req) +static int +nfsiod_read_result(int result, struct nfsiod_req *req) { - struct page *page = (struct page *) req->rq_cdata; + struct nfs_server *server = NFS_SERVER(req->rq_inode); + struct page *page = req->rq_page; static int succ = 0, fail = 0; + int i; dprintk("BIO: received callback for page %p, result %d\n", page, result); - if (result >= 0 - && (result = nfs_proc_read_reply(&req->rq_rpcreq)) >= 0) { - succ++; + if (result >= 0) { + struct nfs_fattr fattr; + + result = nfs_proc_read_reply(&req->rq_rpcreq, &fattr); + if (result >= 0) { + nfs_refresh_inode(req->rq_inode, &fattr); + if (result < PAGE_SIZE) + memset((u8 *) page_address(page)+result, + 0, PAGE_SIZE-result); + } + } else + if (result == -ETIMEDOUT && !(server->flags & NFS_MOUNT_SOFT)) { + /* XXX: Theoretically, we'd have to increment the initial + * timeo here; but I'm not going to bother with this now + * because this old nfsiod stuff will soon die anyway. + */ + result = -EAGAIN; + } + + if (result == -EAGAIN && req->rq_retries--) { + dprintk("BIO: retransmitting request.\n"); + memset(&req->rq_rpcreq, 0, sizeof(struct rpc_ioreq)); + while (rpc_reserve(server->rsock, &req->rq_rpcreq, 1) < 0) + schedule(); + current->fsuid = req->rq_fsuid; + current->fsgid = req->rq_fsgid; + for (i = 0; i < NGROUPS; i++) + current->groups[i] = req->rq_groups[i]; + nfsiod_read_setup(req); + return 0; + } + if (result >= 0) { set_bit(PG_uptodate, &page->flags); + succ++; } else { - fail++; dprintk("BIO: %d successful reads, %d failures\n", succ, fail); set_bit(PG_error, &page->flags); + fail++; } clear_bit(PG_locked, &page->flags); wake_up(&page->wait); free_page(page_address(page)); + return 1; } static inline int do_read_nfs_async(struct inode *inode, struct page *page) { struct nfsiod_req *req; - int result = -1; /* totally arbitrary */ + int result, i; dprintk("NFS: do_read_nfs_async(%p)\n", page); set_bit(PG_locked, &page->flags); clear_bit(PG_error, &page->flags); - if (!(req = nfsiod_reserve(NFS_SERVER(inode), nfs_read_cb))) - goto done; - result = nfs_proc_read_request(&req->rq_rpcreq, - NFS_SERVER(inode), NFS_FH(inode), - page->offset, PAGE_SIZE, - (__u32 *) page_address(page)); - if (result >= 0) { - req->rq_cdata = page; + if (!(req = nfsiod_reserve(NFS_SERVER(inode)))) + return -EAGAIN; + + req->rq_retries = 5; + req->rq_callback = nfsiod_read_result; + req->rq_inode = inode; + req->rq_page = page; + + req->rq_fsuid = current->fsuid; + req->rq_fsgid = current->fsgid; + for (i = 0; i < NGROUPS; i++) + req->rq_groups[i] = current->groups[i]; + + if ((result = nfsiod_read_setup(req)) >= 0) { page->count++; - result = nfsiod_enqueue(req); - if (result >= 0) - dprintk("NFS: enqueued async READ request.\n"); - } - if (result < 0) { + nfsiod_enqueue(req); + } else { dprintk("NFS: deferring async READ request.\n"); nfsiod_release(req); clear_bit(PG_locked, &page->flags); wake_up(&page->wait); } -done: return result < 0? result : 0; } diff -ur --new-file old/linux/fs/nfs/dir.c new/linux/fs/nfs/dir.c --- old/linux/fs/nfs/dir.c Fri May 31 12:46:26 1996 +++ new/linux/fs/nfs/dir.c Sat Jul 20 08:25:25 1996 @@ -32,7 +32,7 @@ static int nfs_link(struct inode *, struct inode *, const char *, int); static int nfs_mknod(struct inode *, const char *, int, int, int); static int nfs_rename(struct inode *, const char *, int, - struct inode *, const char *, int); + struct inode *, const char *, int, int); static struct file_operations nfs_dir_operations = { NULL, /* lseek - default */ @@ -71,14 +71,17 @@ { struct nfs_fattr fattr; - if (jiffies - NFS_READTIME(dir) < server->acdirmax) + if (jiffies - NFS_READTIME(dir) < NFS_ATTRTIMEO(dir)) return; NFS_READTIME(dir) = jiffies; if (nfs_proc_getattr(server, NFS_FH(dir), &fattr) == 0) { nfs_refresh_inode(dir, &fattr); - if (fattr.mtime.seconds == NFS_OLDMTIME(dir)) + if (fattr.mtime.seconds == NFS_OLDMTIME(dir)) { + if ((NFS_ATTRTIMEO(dir) <<= 1) > server->acdirmax) + NFS_ATTRTIMEO(dir) = server->acdirmax; return; + } NFS_OLDMTIME(dir) = fattr.mtime.seconds; } /* invalidate directory cache here when we _really_ start caching */ @@ -505,8 +508,7 @@ return -ENAMETOOLONG; } error = nfs_proc_rmdir(NFS_SERVER(dir), NFS_FH(dir), name); - if (!error) - nfs_lookup_cache_remove(dir, NULL, name); + nfs_lookup_cache_remove(dir, NULL, name); iput(dir); return error; } @@ -531,7 +533,7 @@ return -EIO; /* DWIM */ } ret = nfs_proc_rename(NFS_SERVER(dir), NFS_FH(dir), name, - NFS_FH(dir), silly); + NFS_FH(dir), silly, 0); if (ret >= 0) { nfs_lookup_cache_remove(dir, NULL, name); nfs_lookup_cache_remove(dir, NULL, silly); @@ -571,8 +573,7 @@ } if ((error = nfs_sillyrename(dir, name, len)) < 0) { error = nfs_proc_remove(NFS_SERVER(dir), NFS_FH(dir), name); - if (!error) - nfs_lookup_cache_remove(dir, NULL, name); + nfs_lookup_cache_remove(dir, NULL, name); } iput(dir); return error; @@ -630,15 +631,16 @@ } error = nfs_proc_link(NFS_SERVER(oldinode), NFS_FH(oldinode), NFS_FH(dir), name); - if (!error) - nfs_lookup_cache_remove(dir, oldinode, NULL); + + nfs_lookup_cache_remove(dir, oldinode, NULL); iput(oldinode); iput(dir); return error; } static int nfs_rename(struct inode *old_dir, const char *old_name, int old_len, - struct inode *new_dir, const char *new_name, int new_len) + struct inode *new_dir, const char *new_name, int new_len, + int must_be_dir) { int error; @@ -661,11 +663,11 @@ } error = nfs_proc_rename(NFS_SERVER(old_dir), NFS_FH(old_dir), old_name, - NFS_FH(new_dir), new_name); - if (!error) { - nfs_lookup_cache_remove(old_dir, NULL, old_name); - nfs_lookup_cache_remove(new_dir, NULL, new_name); - } + NFS_FH(new_dir), new_name, + must_be_dir); + + nfs_lookup_cache_remove(old_dir, NULL, old_name); + nfs_lookup_cache_remove(new_dir, NULL, new_name); iput(old_dir); iput(new_dir); return error; @@ -698,6 +700,8 @@ /* Size changed from outside: invalidate caches on next read */ if (inode->i_size != fattr->size) NFS_CACHEINV(inode); + if (NFS_OLDMTIME(inode) != fattr->mtime.seconds) + NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode); inode->i_size = fattr->size; if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) inode->i_rdev = to_kdev_t(fattr->rdev); diff -ur --new-file old/linux/fs/nfs/file.c new/linux/fs/nfs/file.c --- old/linux/fs/nfs/file.c Sat Mar 30 22:57:56 1996 +++ new/linux/fs/nfs/file.c Sat Jul 20 07:56:29 1996 @@ -70,14 +70,17 @@ { struct nfs_fattr fattr; - if (jiffies - NFS_READTIME(inode) < server->acregmax) + if (jiffies - NFS_READTIME(inode) < NFS_ATTRTIMEO(inode)) return; NFS_READTIME(inode) = jiffies; if (nfs_proc_getattr(server, NFS_FH(inode), &fattr) == 0) { nfs_refresh_inode(inode, &fattr); - if (fattr.mtime.seconds == NFS_OLDMTIME(inode)) + if (fattr.mtime.seconds == NFS_OLDMTIME(inode)) { + if ((NFS_ATTRTIMEO(inode) <<= 1) > server->acregmax) + NFS_ATTRTIMEO(inode) = server->acregmax; return; + } NFS_OLDMTIME(inode) = fattr.mtime.seconds; } invalidate_inode_pages(inode); @@ -146,7 +149,9 @@ file->f_pos = pos; if (pos > inode->i_size) inode->i_size = pos; - nfs_refresh_inode(inode, &fattr); + /* Avoid possible Solaris 2.5 nfsd bug */ + if (inode->i_ino == fattr.fileid) + nfs_refresh_inode(inode, &fattr); return written; } diff -ur --new-file old/linux/fs/nfs/nfsiod.c new/linux/fs/nfs/nfsiod.c --- old/linux/fs/nfs/nfsiod.c Sun Apr 7 05:53:36 1996 +++ new/linux/fs/nfs/nfsiod.c Sat Jun 29 11:00:46 1996 @@ -37,7 +37,7 @@ * Reserve an nfsiod slot and initialize the request struct */ struct nfsiod_req * -nfsiod_reserve(struct nfs_server *server, nfsiod_done_fn_t callback) +nfsiod_reserve(struct nfs_server *server) { struct nfsiod_req *req; @@ -56,8 +56,6 @@ } req->rq_server = server; - req->rq_callback = callback; - return req; } @@ -74,21 +72,12 @@ /* * Transmit a request and put it on nfsiod's list of pending requests. */ -int +void nfsiod_enqueue(struct nfsiod_req *req) { - int result; - dprintk("BIO: enqueuing request %p\n", &req->rq_rpcreq); - result = rpc_transmit(req->rq_server->rsock, &req->rq_rpcreq); - if (result < 0) { - dprintk("BIO: rpc_transmit returned %d\n", result); - } else { - dprintk("BIO: waking up nfsiod (%p)\n", req->rq_wait); - wake_up(&req->rq_wait); - schedule(); - } - return result; + wake_up(&req->rq_wait); + schedule(); } /* @@ -120,8 +109,10 @@ current->pid); active++; dprintk("BIO: before: now %d nfsiod's active\n", active); - result = nfs_rpc_doio(req->rq_server, &req->rq_rpcreq, 1); - req->rq_callback(result, req); + do { + result = nfs_rpc_doio(req->rq_server, + &req->rq_rpcreq, 1); + } while (!req->rq_callback(result, req)); active--; } diff -ur --new-file old/linux/fs/nfs/proc.c new/linux/fs/nfs/proc.c --- old/linux/fs/nfs/proc.c Sun Apr 21 16:32:02 1996 +++ new/linux/fs/nfs/proc.c Wed Jul 3 12:52:09 1996 @@ -451,13 +451,12 @@ req->rq_addr = &server->toaddr; req->rq_alen = sizeof(server->toaddr); - return 0; + return rpc_transmit(server->rsock, req); } int -nfs_proc_read_reply(struct rpc_ioreq *req) +nfs_proc_read_reply(struct rpc_ioreq *req, struct nfs_fattr *fattr) { - struct nfs_fattr fattr; int status; __u32 *p0, *p; int count; @@ -465,9 +464,11 @@ p0 = (__u32 *) req->rq_rvec[0].iov_base; if (!(p = nfs_rpc_verify(p0))) { - status = -errno_NFSERR_IO; + /* Tell the upper layers to retry */ + status = -EAGAIN; + /* status = -errno_NFSERR_IO; */ } else if ((status = ntohl(*p++)) == NFS_OK) { - p = xdr_decode_fattr(p, &fattr); + p = xdr_decode_fattr(p, fattr); count = ntohl(*p++); if (p != req->rq_rvec[2].iov_base) { /* unexpected RPC reply header size. punt. @@ -612,12 +613,19 @@ int nfs_proc_rename(struct nfs_server *server, struct nfs_fh *old_dir, const char *old_name, - struct nfs_fh *new_dir, const char *new_name) + struct nfs_fh *new_dir, const char *new_name, + int must_be_dir) { int *p, *p0; int status; int ruid = 0; + /* + * Disallow "rename()" with trailing slashes over NFS: getting + * POSIX.1 behaviour is just too unlikely. + */ + if (must_be_dir) + return -EINVAL; PRINTK("NFS call rename %s -> %s\n", old_name, new_name); if (!(p0 = nfs_rpc_alloc(server->wsize))) return -EIO; diff -ur --new-file old/linux/fs/open.c new/linux/fs/open.c --- old/linux/fs/open.c Mon May 27 14:47:32 1996 +++ new/linux/fs/open.c Tue Aug 20 10:59:19 1996 @@ -17,8 +17,10 @@ #include #include #include +#include #include +#include asmlinkage int sys_statfs(const char * path, struct statfs * buf) { @@ -53,6 +55,8 @@ return -EBADF; if (!(inode = file->f_inode)) return -ENOENT; + if (!inode->i_sb) + return -ENODEV; if (!inode->i_sb->s_op->statfs) return -ENOSYS; inode->i_sb->s_op->statfs(inode->i_sb, buf, sizeof(struct statfs)); @@ -181,7 +185,8 @@ newattrs.ia_mtime = get_user(×->modtime); newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET; } else { - if ((error = permission(inode,MAY_WRITE)) != 0) { + if (current->fsuid != inode->i_uid && + (error = permission(inode,MAY_WRITE)) != 0) { iput(inode); return error; } @@ -397,7 +402,7 @@ /* * If the owner has been changed, remove the setuid bit */ - if (user != inode->i_uid && (inode->i_mode & S_ISUID)) { + if (inode->i_mode & S_ISUID) { newattrs.ia_mode &= ~S_ISUID; newattrs.ia_valid |= ATTR_MODE; } @@ -407,8 +412,7 @@ * Don't remove the setgid bit if no group execute bit. * This is a file marked for mandatory locking. */ - if (group != inode->i_gid && - ((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))) { + if (((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))) { newattrs.ia_mode &= ~S_ISGID; newattrs.ia_valid |= ATTR_MODE; } @@ -453,7 +457,7 @@ /* * If the owner has been changed, remove the setuid bit */ - if (user != inode->i_uid && (inode->i_mode & S_ISUID)) { + if (inode->i_mode & S_ISUID) { newattrs.ia_mode &= ~S_ISUID; newattrs.ia_valid |= ATTR_MODE; } @@ -463,8 +467,7 @@ * Don't remove the setgid bit if no group execute bit. * This is a file marked for mandatory locking. */ - if (group != inode->i_gid && - ((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))) { + if (((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))) { newattrs.ia_mode &= ~S_ISGID; newattrs.ia_valid |= ATTR_MODE; } @@ -496,11 +499,11 @@ * for the internal routines (ie open_namei()/follow_link() etc). 00 is * used by symlinks. */ -int do_open(const char * filename,int flags,int mode) +static int do_open(const char * filename,int flags,int mode, int fd) { struct inode * inode; struct file * f; - int flag,error,fd; + int flag,error; f = get_empty_filp(); if (!f) @@ -509,7 +512,7 @@ f->f_mode = (flag+1) & O_ACCMODE; if (f->f_mode) flag++; - if (flag & (O_TRUNC | O_CREAT)) + if (flag & O_TRUNC) flag |= 2; error = open_namei(filename,flag,mode,&inode,NULL); if (error) @@ -533,21 +536,9 @@ } f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); - /* - * We have to do this last, because we mustn't export - * an incomplete fd to other processes which may share - * the same file table with us. - */ - for(fd = 0; fd < NR_OPEN && fd < current->rlim[RLIMIT_NOFILE].rlim_cur; fd++) { - if (!current->files->fd[fd]) { - current->files->fd[fd] = f; - FD_CLR(fd,¤t->files->close_on_exec); - return fd; - } - } - error = -EMFILE; - if (f->f_op && f->f_op->release) - f->f_op->release(inode,f); + current->files->fd[fd] = f; + return 0; + cleanup_all: if (f->f_mode & FMODE_WRITE) put_write_access(inode); @@ -558,16 +549,44 @@ return error; } +/* + * Find a empty file descriptor entry, and mark it busy + */ +int get_unused_fd(void) +{ + int fd; + struct files_struct * files = current->files; + + fd = find_first_zero_bit(&files->open_fds, NR_OPEN); + if (fd < current->rlim[RLIMIT_NOFILE].rlim_cur) { + FD_SET(fd, &files->open_fds); + FD_CLR(fd, &files->close_on_exec); + return fd; + } + return -EMFILE; +} + +inline void put_unused_fd(int fd) +{ + FD_CLR(fd, ¤t->files->open_fds); +} + asmlinkage int sys_open(const char * filename,int flags,int mode) { char * tmp; - int error; + int fd, error; + fd = get_unused_fd(); + if (fd < 0) + return fd; error = getname(filename, &tmp); - if (error) - return error; - error = do_open(tmp,flags,mode); - putname(tmp); + if (!error) { + error = do_open(tmp,flags,mode, fd); + putname(tmp); + if (!error) + return fd; + } + put_unused_fd(fd); return error; } @@ -584,6 +603,16 @@ #endif +void __fput(struct file *filp, struct inode *inode) +{ + if (filp->f_op && filp->f_op->release) + filp->f_op->release(inode,filp); + filp->f_inode = NULL; + if (filp->f_mode & FMODE_WRITE) + put_write_access(inode); + iput(inode); +} + int close_fp(struct file *filp) { struct inode *inode; @@ -595,31 +624,25 @@ inode = filp->f_inode; if (inode) locks_remove_locks(current, filp); - if (filp->f_count > 1) { - filp->f_count--; - return 0; - } - if (filp->f_op && filp->f_op->release) - filp->f_op->release(inode,filp); - filp->f_count--; - filp->f_inode = NULL; - if (filp->f_mode & FMODE_WRITE) - put_write_access(inode); - iput(inode); + fput(filp, inode); return 0; } asmlinkage int sys_close(unsigned int fd) -{ +{ + int error; struct file * filp; + struct files_struct * files; - if (fd >= NR_OPEN) - return -EBADF; - FD_CLR(fd, ¤t->files->close_on_exec); - if (!(filp = current->files->fd[fd])) - return -EBADF; - current->files->fd[fd] = NULL; - return (close_fp (filp)); + files = current->files; + error = -EBADF; + if (fd < NR_OPEN && (filp = files->fd[fd]) != NULL) { + put_unused_fd(fd); + FD_CLR(fd, &files->close_on_exec); + files->fd[fd] = NULL; + error = close_fp(filp); + } + return error; } /* diff -ur --new-file old/linux/fs/pipe.c new/linux/fs/pipe.c --- old/linux/fs/pipe.c Fri May 3 09:24:07 1996 +++ new/linux/fs/pipe.c Sun Jul 7 19:27:04 1996 @@ -67,8 +67,10 @@ } PIPE_LOCK(*inode)--; wake_up_interruptible(&PIPE_WAIT(*inode)); - if (read) + if (read) { + inode->i_atime = CURRENT_TIME; return read; + } if (PIPE_WRITERS(*inode)) return -EAGAIN; return 0; @@ -118,6 +120,7 @@ wake_up_interruptible(&PIPE_WAIT(*inode)); free = 1; } + inode->i_ctime = inode->i_mtime = CURRENT_TIME; return written; } @@ -213,16 +216,8 @@ */ static int connect_read(struct inode * inode, struct file * filp, char * buf, int count) { - while (!PIPE_SIZE(*inode)) { - if (PIPE_WRITERS(*inode)) - break; - if (filp->f_flags & O_NONBLOCK) - return -EAGAIN; - wake_up_interruptible(& PIPE_WAIT(*inode)); - if (current->signal & ~current->blocked) - return -ERESTARTSYS; - interruptible_sleep_on(& PIPE_WAIT(*inode)); - } + if (PIPE_EMPTY(*inode) && !PIPE_WRITERS(*inode)) + return 0; filp->f_op = &read_fifo_fops; return pipe_read(inode,filp,buf,count); } @@ -235,6 +230,9 @@ filp->f_op = &read_fifo_fops; return 1; } + if (PIPE_WRITERS(*inode)) { + filp->f_op = &read_fifo_fops; + } select_wait(&PIPE_WAIT(*inode), wait); return 0; case SEL_OUT: @@ -411,45 +409,58 @@ int do_pipe(int *fd) { struct inode * inode; - struct file *f[2]; + struct file *f1, *f2; + int error; int i,j; + error = ENFILE; + f1 = get_empty_filp(); + if (!f1) + goto no_files; + + f2 = get_empty_filp(); + if (!f2) + goto close_f1; + inode = get_pipe_inode(); if (!inode) - return -ENFILE; + goto close_f12; - for(j=0 ; j<2 ; j++) - if (!(f[j] = get_empty_filp())) - break; - if (j < 2) { - iput(inode); - iput(inode); - if (j) - f[0]->f_count--; - return -ENFILE; - } - j=0; - for(i=0;j<2 && irlim[RLIMIT_NOFILE].rlim_cur;i++) - if (!current->files->fd[i]) { - current->files->fd[ fd[j]=i ] = f[j]; - j++; - } - if (j<2) { - iput(inode); - iput(inode); - f[0]->f_count--; - f[1]->f_count--; - if (j) - current->files->fd[fd[0]] = NULL; - return -EMFILE; - } - f[0]->f_inode = f[1]->f_inode = inode; - f[0]->f_pos = f[1]->f_pos = 0; - f[0]->f_flags = O_RDONLY; - f[0]->f_op = &read_pipe_fops; - f[0]->f_mode = 1; /* read */ - f[1]->f_flags = O_WRONLY; - f[1]->f_op = &write_pipe_fops; - f[1]->f_mode = 2; /* write */ + error = get_unused_fd(); + if (error < 0) + goto close_f12_inode; + i = error; + + error = get_unused_fd(); + if (error < 0) + goto close_f12_inode_i; + j = error; + + f1->f_inode = f2->f_inode = inode; + /* read file */ + f1->f_pos = f2->f_pos = 0; + f1->f_flags = O_RDONLY; + f1->f_op = &read_pipe_fops; + f1->f_mode = 1; + /* write file */ + f2->f_flags = O_WRONLY; + f2->f_op = &write_pipe_fops; + f2->f_mode = 2; + current->files->fd[i] = f1; + current->files->fd[j] = f2; + fd[0] = i; + fd[1] = j; return 0; + +close_f12_inode_i: + put_unused_fd(i); +close_f12_inode: + inode->i_count--; + iput(inode); +close_f12: + f2->f_count--; +close_f1: + f1->f_count--; +no_files: + return error; } diff -ur --new-file old/linux/fs/proc/array.c new/linux/fs/proc/array.c --- old/linux/fs/proc/array.c Tue Apr 30 12:09:45 1996 +++ new/linux/fs/proc/array.c Mon Aug 12 08:14:46 1996 @@ -25,6 +25,9 @@ * * Bruno Haible : remove 4K limit for the maps file * + * + * Yves Arrouye : remove removal of trailing spaces in get_array. + * */ #include @@ -370,7 +373,7 @@ for (;;) { addr = get_phys_addr(*p, start); if (!addr) - goto ready; + return result; do { c = *(char *) addr; if (!c) @@ -378,17 +381,13 @@ if (size < PAGE_SIZE) buffer[size++] = c; else - goto ready; + return result; addr++; start++; if (!c && start >= end) - goto ready; + return result; } while (addr & ~PAGE_MASK); } -ready: - /* remove the trailing blanks, used to fill out argv,envp space */ - while (result>0 && buffer[result-1]==' ') - result--; return result; } @@ -428,8 +427,8 @@ if (ebp < stack_page || ebp >= 4092+stack_page) return 0; eip = *(unsigned long *) (ebp+4); - if ((void *)eip != sleep_on && - (void *)eip != interruptible_sleep_on) + if (eip < (unsigned long) interruptible_sleep_on + || eip >= (unsigned long) add_timer) return eip; ebp = *(unsigned long *) ebp; } while (count++ < 16); @@ -861,8 +860,13 @@ * f_pos = (number of the vma in the task->mm->mmap list) * MAPS_LINE_LENGTH * + (index into the line) */ +#ifdef __alpha__ +#define MAPS_LINE_FORMAT "%016lx-%016lx %s %016lx %s %lu\n" +#define MAPS_LINE_MAX 73 /* sum of 16 1 16 1 4 1 16 1 5 1 10 1 */ +#else #define MAPS_LINE_FORMAT "%08lx-%08lx %s %08lx %s %lu\n" #define MAPS_LINE_MAX 49 /* sum of 8 1 8 1 4 1 8 1 5 1 10 1 */ +#endif static int read_maps (int pid, struct file * file, char * buf, int count) { diff -ur --new-file old/linux/fs/read_write.c new/linux/fs/read_write.c --- old/linux/fs/read_write.c Thu Jun 6 20:22:24 1996 +++ new/linux/fs/read_write.c Tue Aug 20 10:43:57 1996 @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -106,21 +107,33 @@ struct file * file; struct inode * inode; - if (fd>=NR_OPEN || !(file=current->files->fd[fd]) || !(inode=file->f_inode)) - return -EBADF; + error = -EBADF; + file = fget(fd); + if (!file) + goto bad_file; + inode = file->f_inode; + if (!inode) + goto out; + error = -EBADF; if (!(file->f_mode & 1)) - return -EBADF; + goto out; + error = -EINVAL; if (!file->f_op || !file->f_op->read) - return -EINVAL; + goto out; + error = 0; if (count <= 0) - return 0; + goto out; error = locks_verify_area(FLOCK_VERIFY_READ,inode,file,file->f_pos,count); if (error) - return error; + goto out; error = verify_area(VERIFY_WRITE,buf,count); if (error) - return error; - return file->f_op->read(inode,file,buf,count); + goto out; + error = file->f_op->read(inode,file,buf,count); +out: + fput(file, inode); +bad_file: + return error; } asmlinkage int sys_write(unsigned int fd,char * buf,unsigned int count) @@ -128,22 +141,28 @@ int error; struct file * file; struct inode * inode; - int written; - - if (fd>=NR_OPEN || !(file=current->files->fd[fd]) || !(inode=file->f_inode)) - return -EBADF; + + error = -EBADF; + file = fget(fd); + if (!file) + goto bad_file; + inode = file->f_inode; + if (!inode) + goto out; if (!(file->f_mode & 2)) - return -EBADF; + goto out; + error = -EINVAL; if (!file->f_op || !file->f_op->write) - return -EINVAL; + goto out; + error = 0; if (!count) - return 0; + goto out; error = locks_verify_area(FLOCK_VERIFY_WRITE,inode,file,file->f_pos,count); if (error) - return error; + goto out; error = verify_area(VERIFY_READ,buf,count); if (error) - return error; + goto out; /* * If data has been written to the file, remove the setuid and * the setgid bits. We do it anyway otherwise there is an @@ -164,9 +183,12 @@ } down(&inode->i_sem); - written = file->f_op->write(inode,file,buf,count); + error = file->f_op->write(inode,file,buf,count); up(&inode->i_sem); - return written; +out: + fput(file, inode); +bad_file: + return error; } static int sock_readv_writev(int type, struct inode * inode, struct file * file, diff -ur --new-file old/linux/fs/select.c new/linux/fs/select.c --- old/linux/fs/select.c Wed Sep 27 08:57:19 1995 +++ new/linux/fs/select.c Fri Jul 5 12:48:39 1996 @@ -92,11 +92,13 @@ int i,j; int max = -1; - for (j = 0 ; j < __FDSET_INTS ; j++) { + j = 0; + for (;;) { i = j * __NFDBITS; if (i >= n) break; set = in->fds_bits[j] | out->fds_bits[j] | ex->fds_bits[j]; + j++; for ( ; set ; i++,set >>= 1) { if (i >= n) goto end_check; @@ -113,9 +115,6 @@ n = max + 1; if(!(entry = (struct select_table_entry*) __get_free_page(GFP_KERNEL))) return -ENOMEM; - FD_ZERO(res_in); - FD_ZERO(res_out); - FD_ZERO(res_ex); count = 0; wait_table.nr = 0; wait_table.entry = entry; @@ -153,51 +152,79 @@ /* * We do a VERIFY_WRITE here even though we are only reading this time: * we'll write to it eventually.. + * + * Use "int" accesses to let user-mode fd_set's be int-aligned. */ -static int __get_fd_set(int nr, unsigned int * fs_pointer, fd_set * fdset) +static int __get_fd_set(unsigned long nr, int * fs_pointer, int * fdset) { - int error, i; - unsigned int * tmp; - - FD_ZERO(fdset); - if (!fs_pointer) - return 0; - error = verify_area(VERIFY_WRITE,fs_pointer,sizeof(fd_set)); - if (error) + /* round up nr to nearest "int" */ + nr = (nr + 8*sizeof(int)-1) / (8*sizeof(int)); + if (fs_pointer) { + int error = verify_area(VERIFY_WRITE,fs_pointer,nr*sizeof(int)); + if (!error) { + while (nr) { + *fdset = get_user(fs_pointer); + nr--; + fs_pointer++; + fdset++; + } + } return error; - tmp = fdset->fds_bits; - for (i = __FDSET_INTS; i > 0; i--) { - if (nr <= 0) - break; - *tmp = get_user(fs_pointer); - tmp++; - fs_pointer++; - nr -= 8 * sizeof(unsigned int); + } + while (nr) { + *fdset = 0; + nr--; + fdset++; } return 0; } -static void __set_fd_set(int nr, unsigned int * fs_pointer, unsigned int * fdset) +static void __set_fd_set(long nr, int * fs_pointer, int * fdset) { - int i; - if (!fs_pointer) return; - for (i = __FDSET_INTS; i > 0; i--) { - if (nr <= 0) - break; + while (nr >= 0) { put_user(*fdset, fs_pointer); + nr -= 8 * sizeof(int); fdset++; fs_pointer++; - nr -= 8 * sizeof(unsigned int); } } +/* We can do long accesses here, kernel fdsets are always long-aligned */ +static inline void __zero_fd_set(long nr, unsigned long * fdset) +{ + while (nr >= 0) { + *fdset = 0; + nr -= 8 * sizeof(unsigned long); + fdset++; + } +} + +/* + * Due to kernel stack usage, we use a _limited_ fd_set type here, and once + * we really start supporting >256 file descriptors we'll probably have to + * allocate the kernel fd_set copies dynamically.. (The kernel select routines + * are careful to touch only the defined low bits of any fd_set pointer, this + * is important for performance too). + * + * Note a few subtleties: we use "long" for the dummy, not int, and we do a + * subtract by 1 on the nr of file descriptors. The former is better for + * machines with long > int, and the latter allows us to test the bit count + * against "zero or positive", which can mostly be just a sign bit test.. + */ +typedef struct { + unsigned long dummy[NR_OPEN/(8*(sizeof(unsigned long)))]; +} limited_fd_set; + #define get_fd_set(nr,fsp,fdp) \ -__get_fd_set(nr, (unsigned int *) (fsp), fdp) +__get_fd_set(nr, (int *) (fsp), (int *) (fdp)) #define set_fd_set(nr,fsp,fdp) \ -__set_fd_set(nr, (unsigned int *) (fsp), (unsigned int *) (fdp)) +__set_fd_set((nr)-1, (int *) (fsp), (int *) (fdp)) + +#define zero_fd_set(nr,fdp) \ +__zero_fd_set((nr)-1, (unsigned long *) (fdp)) /* * We can actually return ERESTARTSYS instead of EINTR, but I'd @@ -209,31 +236,41 @@ */ asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp) { - int i; - fd_set res_in, in; - fd_set res_out, out; - fd_set res_ex, ex; + int error; + limited_fd_set res_in, in; + limited_fd_set res_out, out; + limited_fd_set res_ex, ex; unsigned long timeout; + error = -EINVAL; if (n < 0) - return -EINVAL; + goto out; if (n > NR_OPEN) n = NR_OPEN; - if ((i = get_fd_set(n, inp, &in)) || - (i = get_fd_set(n, outp, &out)) || - (i = get_fd_set(n, exp, &ex))) return i; + if ((error = get_fd_set(n, inp, &in)) || + (error = get_fd_set(n, outp, &out)) || + (error = get_fd_set(n, exp, &ex))) goto out; timeout = ~0UL; if (tvp) { - i = verify_area(VERIFY_WRITE, tvp, sizeof(*tvp)); - if (i) - return i; + error = verify_area(VERIFY_WRITE, tvp, sizeof(*tvp)); + if (error) + goto out; timeout = ROUND_UP(get_user(&tvp->tv_usec),(1000000/HZ)); timeout += get_user(&tvp->tv_sec) * (unsigned long) HZ; if (timeout) timeout += jiffies + 1; } + zero_fd_set(n, &res_in); + zero_fd_set(n, &res_out); + zero_fd_set(n, &res_ex); current->timeout = timeout; - i = do_select(n, &in, &out, &ex, &res_in, &res_out, &res_ex); + error = do_select(n, + (fd_set *) &in, + (fd_set *) &out, + (fd_set *) &ex, + (fd_set *) &res_in, + (fd_set *) &res_out, + (fd_set *) &res_ex); timeout = current->timeout - jiffies - 1; current->timeout = 0; if ((long) timeout < 0) @@ -244,12 +281,17 @@ timeout *= (1000000/HZ); put_user(timeout, &tvp->tv_usec); } - if (i < 0) - return i; - if (!i && (current->signal & ~current->blocked)) - return -ERESTARTNOHAND; + if (error < 0) + goto out; + if (!error) { + error = -ERESTARTNOHAND; + if (current->signal & ~current->blocked) + goto out; + error = 0; + } set_fd_set(n, inp, &res_in); set_fd_set(n, outp, &res_out); set_fd_set(n, exp, &res_ex); - return i; +out: + return error; } diff -ur --new-file old/linux/fs/smbfs/dir.c new/linux/fs/smbfs/dir.c --- old/linux/fs/smbfs/dir.c Wed Jun 5 12:22:47 1996 +++ new/linux/fs/smbfs/dir.c Wed Jul 3 11:09:32 1996 @@ -61,7 +61,8 @@ static int smb_rename(struct inode *old_dir, const char *old_name, int old_len, - struct inode *new_dir, const char *new_name, int new_len); + struct inode *new_dir, const char *new_name, int new_len, + int must_be_dir); static inline void str_upper(char *name) { @@ -882,7 +883,8 @@ static int smb_rename(struct inode *old_dir, const char *old_name, int old_len, - struct inode *new_dir, const char *new_name, int new_len) + struct inode *new_dir, const char *new_name, int new_len, + int must_be_dir) { int res; char old_path[SMB_MAXPATHLEN], new_path[SMB_MAXPATHLEN]; diff -ur --new-file old/linux/fs/smbfs/proc.c new/linux/fs/smbfs/proc.c --- old/linux/fs/smbfs/proc.c Wed Jun 5 12:22:48 1996 +++ new/linux/fs/smbfs/proc.c Thu Jul 11 12:52:06 1996 @@ -3,6 +3,7 @@ * * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke * + * 28/06/96 - Fixed long file name support (smb_proc_readdir_long) by Yuri Per */ #include @@ -305,7 +306,7 @@ case ERRdiffdevice: return EXDEV; case ERRnofiles: return 0; case ERRbadshare: return ETXTBSY; - case ERRlock: return EDEADLOCK; + case ERRlock: return EDEADLK; case ERRfilexists: return EEXIST; case 87: return 0; /* Unknown error!! */ /* This next error seems to occur on an mv when @@ -330,7 +331,7 @@ case ERRdata: return EIO; case ERRbadreq: return ERANGE; case ERRbadshare: return ETXTBSY; - case ERRlock: return EDEADLOCK; + case ERRlock: return EDEADLK; default: return EIO; } else if (errcls == ERRCMD) @@ -1152,6 +1153,7 @@ int info_level = 1; char *p; + char *lastname; int i; int first, total_count; struct smb_dirent *current_entry; @@ -1171,9 +1173,15 @@ int ff_dir_handle=0; int loop_count = 0; - int dirlen = strlen(SMB_FINFO(dir)->path); - char mask[dirlen + 5]; + int dirlen = strlen(SMB_FINFO(dir)->path) + 3; + char *mask; + mask = smb_kmalloc(dirlen, GFP_KERNEL); + if (mask == NULL) + { + printk("smb_proc_readdir_long: Memory allocation failed\n"); + return -ENOMEM; + } strcpy(mask, SMB_FINFO(dir)->path); strcat(mask, "\\*"); @@ -1297,22 +1305,37 @@ p = resp_data; /* we might need the lastname for continuations */ + lastname = ""; if (ff_lastname > 0) { switch(info_level) { case 260: - ff_resume_key =0; - strcpy(mask,p+ff_lastname+94); + lastname = p + ff_lastname + 94; + ff_resume_key = 0; break; case 1: - strcpy(mask,p + ff_lastname + 1); + lastname = p + ff_lastname + 1; ff_resume_key = 0; break; } } - else - strcpy(mask,""); + + /* Increase size of mask, if it is too small */ + i = strlen(lastname) + 1; + if (i > dirlen) + { + smb_kfree_s(mask, 0); + dirlen = i; + mask = smb_kmalloc(dirlen, GFP_KERNEL); + if (mask == NULL) + { + printk("smb_proc_readdir_long: Memory allocation failed\n"); + result = -ENOMEM; + break; + } + strcpy(mask, lastname); + } /* Now we are ready to parse smb directory entries. */ @@ -1355,6 +1378,9 @@ } finished: + if (mask != NULL) + smb_kfree_s(mask, 0); + if (resp_data != NULL) { smb_kfree_s(resp_data, 0); resp_data = NULL; @@ -1713,7 +1739,7 @@ DPRINTK("smb_proc_connect: Server wants %s protocol.\n", prots[i].name); - if (server->protocol > PROTOCOL_LANMAN1) { + if (server->protocol >= PROTOCOL_LANMAN1) { word passlen = strlen(server->m.password); word userlen = strlen(server->m.username); diff -ur --new-file old/linux/fs/super.c new/linux/fs/super.c --- old/linux/fs/super.c Sat Jun 8 10:10:49 1996 +++ new/linux/fs/super.c Tue Aug 6 08:10:48 1996 @@ -967,6 +967,9 @@ #ifdef CONFIG_BLK_DEV_FD if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) { floppy_eject(); +#ifndef CONFIG_BLK_DEV_RAM + printk(KERN_NOTICE "(Warning, this kernel has no ramdisk support)\n"); +#endif printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER\n"); wait_for_keypress(); } @@ -1065,7 +1068,7 @@ umount_error = do_umount(old_root_dev,1); if (umount_error) printk(KERN_ERR "error %d\n",umount_error); else { - printk(KERN_NOTICE "okay\n"); + printk("okay\n"); invalidate_buffers(old_root_dev); } return umount_error ? error : 0; diff -ur --new-file old/linux/fs/sysv/namei.c new/linux/fs/sysv/namei.c --- old/linux/fs/sysv/namei.c Wed Nov 8 11:36:10 1995 +++ new/linux/fs/sysv/namei.c Wed Jul 3 11:06:03 1996 @@ -668,7 +668,7 @@ * higher-level routines. */ static int do_sysv_rename(struct inode * old_dir, const char * old_name, int old_len, - struct inode * new_dir, const char * new_name, int new_len) + struct inode * new_dir, const char * new_name, int new_len, int must_be_dir) { struct inode * old_inode, * new_inode; struct buffer_head * old_bh, * new_bh, * dir_bh; @@ -694,6 +694,8 @@ old_inode = __iget(old_dir->i_sb, old_de->inode, 0); /* don't cross mnt-points */ if (!old_inode) goto end_rename; + if (must_be_dir && !S_ISDIR(old_inode->i_mode)) + goto end_rename; retval = -EPERM; if ((old_dir->i_mode & S_ISVTX) && current->fsuid != old_inode->i_uid && @@ -808,7 +810,8 @@ * as they are on different partitions. */ int sysv_rename(struct inode * old_dir, const char * old_name, int old_len, - struct inode * new_dir, const char * new_name, int new_len) + struct inode * new_dir, const char * new_name, int new_len, + int must_be_dir) { static struct wait_queue * wait = NULL; static int lock = 0; @@ -818,7 +821,7 @@ sleep_on(&wait); lock = 1; result = do_sysv_rename(old_dir, old_name, old_len, - new_dir, new_name, new_len); + new_dir, new_name, new_len, must_be_dir); lock = 0; wake_up(&wait); return result; diff -ur --new-file old/linux/fs/ufs/ufs_super.c new/linux/fs/ufs/ufs_super.c --- old/linux/fs/ufs/ufs_super.c Tue May 21 06:05:22 1996 +++ new/linux/fs/ufs/ufs_super.c Mon Jul 8 09:21:46 1996 @@ -129,7 +129,13 @@ /* XXX - redo this so we can free it later... */ usb = (struct ufs_superblock *)__get_free_page(GFP_KERNEL); if (usb == NULL) { + sb->s_dev=0; + unlock_super(sb); + brelse(bh1); + brelse(bh2); printk ("ufs_read_super: get_free_page() failed\n"); + MOD_DEC_USE_COUNT; + return (NULL); } memcpy((char *)usb, bh1->b_data, BLOCK_SIZE); diff -ur --new-file old/linux/fs/umsdos/ioctl.c new/linux/fs/umsdos/ioctl.c --- old/linux/fs/umsdos/ioctl.c Sun Mar 24 19:07:00 1996 +++ new/linux/fs/umsdos/ioctl.c Wed Jul 3 15:39:48 1996 @@ -219,7 +219,7 @@ ret = msdos_rename (dir ,data.dos_dirent.d_name,data.dos_dirent.d_reclen ,dir - ,data.umsdos_dirent.name,data.umsdos_dirent.name_len); + ,data.umsdos_dirent.name,data.umsdos_dirent.name_len,0); }else if (cmd == UMSDOS_UNLINK_EMD){ /* #Specification: ioctl / UMSDOS_UNLINK_EMD The umsdos_dirent field of the struct umsdos_ioctl is used diff -ur --new-file old/linux/fs/umsdos/namei.c new/linux/fs/umsdos/namei.c --- old/linux/fs/umsdos/namei.c Mon May 6 11:26:15 1996 +++ new/linux/fs/umsdos/namei.c Wed Jul 3 15:41:31 1996 @@ -353,7 +353,8 @@ ret = msdos_rename (old_dir ,old_info.fake.fname,old_info.fake.len ,new_dir - ,new_info.fake.fname,new_info.fake.len); + ,new_info.fake.fname,new_info.fake.len + ,0); chkstk(); PRINTK (("after m_rename ret %d ",ret)); if (ret != 0){ @@ -1014,7 +1015,8 @@ int old_len, struct inode * new_dir, const char * new_name, - int new_len) + int new_len, + int must_be_dir) { /* #Specification: weakness / rename There is a case where UMSDOS rename has a different behavior diff -ur --new-file old/linux/fs/vfat/namei.c new/linux/fs/vfat/namei.c --- old/linux/fs/vfat/namei.c Fri May 10 06:54:52 1996 +++ new/linux/fs/vfat/namei.c Wed Jul 3 10:58:01 1996 @@ -1352,7 +1352,7 @@ int vfat_rename(struct inode *old_dir,const char *old_name,int old_len, - struct inode *new_dir,const char *new_name,int new_len) + struct inode *new_dir,const char *new_name,int new_len,int must_be_dir) { struct super_block *sb = old_dir->i_sb; struct buffer_head *old_bh,*new_bh,*dotdot_bh; @@ -1383,8 +1383,12 @@ PRINTK(("vfat_rename 3\n")); if (res < 0) goto rename_done; - if (!(old_inode = iget(old_dir->i_sb,old_ino))) goto rename_done; + res = -ENOENT; + if (!(old_inode = iget(old_dir->i_sb,old_ino))) + goto rename_done; is_dir = S_ISDIR(old_inode->i_mode); + if (must_be_dir && !is_dir) + goto rename_done; if (is_dir) { if ((old_dir->i_dev != new_dir->i_dev) || (old_ino == new_dir->i_ino)) { diff -ur --new-file old/linux/fs/xiafs/namei.c new/linux/fs/xiafs/namei.c --- old/linux/fs/xiafs/namei.c Wed Nov 8 11:32:32 1995 +++ new/linux/fs/xiafs/namei.c Wed Jul 3 15:28:55 1996 @@ -713,7 +713,8 @@ */ static int do_xiafs_rename(struct inode * old_dir, const char * old_name, int old_len, struct inode * new_dir, - const char * new_name, int new_len) + const char * new_name, int new_len, + int must_be_dir) { struct inode * old_inode, * new_inode; struct buffer_head * old_bh, * new_bh, * dir_bh; @@ -730,6 +731,8 @@ old_inode = __iget(old_dir->i_sb, old_de->d_ino, 0); /* don't cross mnt-points */ if (!old_inode) goto end_rename; + if (must_be_dir && !S_ISDIR(old_inode->i_mode)) + goto end_rename; retval = -EPERM; if ((old_dir->i_mode & S_ISVTX) && current->fsuid != old_inode->i_uid && @@ -832,7 +835,8 @@ * as they are on different partitions. */ int xiafs_rename(struct inode * old_dir, const char * old_name, int old_len, - struct inode * new_dir, const char * new_name, int new_len) + struct inode * new_dir, const char * new_name, int new_len, + int must_be_dir) { static struct wait_queue * wait = NULL; static int lock = 0; @@ -842,7 +846,8 @@ sleep_on(&wait); lock = 1; result = do_xiafs_rename(old_dir, old_name, old_len, - new_dir, new_name, new_len); + new_dir, new_name, new_len, + must_be_dir); lock = 0; wake_up(&wait); return result; diff -ur --new-file old/linux/include/asm-alpha/apecs.h new/linux/include/asm-alpha/apecs.h --- old/linux/include/asm-alpha/apecs.h Tue Jun 4 05:06:38 1996 +++ new/linux/include/asm-alpha/apecs.h Tue Jul 9 07:08:18 1996 @@ -414,6 +414,7 @@ /* * Data structure for handling APECS machine checks: */ +#ifdef CONFIG_ALPHA_MIKASA struct el_apecs_sysdata_mcheck { unsigned long coma_gcr; unsigned long coma_edsr; @@ -425,9 +426,11 @@ unsigned long coma_base0; unsigned long coma_base1; unsigned long coma_base2; + unsigned long coma_base3; unsigned long coma_cnfg0; unsigned long coma_cnfg1; unsigned long coma_cnfg2; + unsigned long coma_cnfg3; unsigned long epic_dcsr; unsigned long epic_pear; unsigned long epic_sear; @@ -456,7 +459,100 @@ unsigned long epic_data5; unsigned long epic_data6; unsigned long epic_data7; + + unsigned long pceb_vid; + unsigned long pceb_did; + unsigned long pceb_revision; + unsigned long pceb_command; + unsigned long pceb_status; + unsigned long pceb_latency; + unsigned long pceb_control; + unsigned long pceb_arbcon; + unsigned long pceb_arbpri; + + unsigned long esc_id; + unsigned long esc_revision; + unsigned long esc_int0; + unsigned long esc_int1; + unsigned long esc_elcr0; + unsigned long esc_elcr1; + unsigned long esc_last_eisa; + unsigned long esc_nmi_stat; + + unsigned long pci_ir; + unsigned long pci_imr; + unsigned long svr_mgr; }; +#else /* CONFIG_ALPHA_MIKASA */ +/* this for the normal APECS machines */ +struct el_apecs_sysdata_mcheck { + unsigned long coma_gcr; + unsigned long coma_edsr; + unsigned long coma_ter; + unsigned long coma_elar; + unsigned long coma_ehar; + unsigned long coma_ldlr; + unsigned long coma_ldhr; + unsigned long coma_base0; + unsigned long coma_base1; + unsigned long coma_base2; + unsigned long coma_cnfg0; + unsigned long coma_cnfg1; + unsigned long coma_cnfg2; + unsigned long epic_dcsr; + unsigned long epic_pear; + unsigned long epic_sear; + unsigned long epic_tbr1; + unsigned long epic_tbr2; + unsigned long epic_pbr1; + unsigned long epic_pbr2; + unsigned long epic_pmr1; + unsigned long epic_pmr2; + unsigned long epic_harx1; + unsigned long epic_harx2; + unsigned long epic_pmlt; + unsigned long epic_tag0; + unsigned long epic_tag1; + unsigned long epic_tag2; + unsigned long epic_tag3; + unsigned long epic_tag4; + unsigned long epic_tag5; + unsigned long epic_tag6; + unsigned long epic_tag7; + unsigned long epic_data0; + unsigned long epic_data1; + unsigned long epic_data2; + unsigned long epic_data3; + unsigned long epic_data4; + unsigned long epic_data5; + unsigned long epic_data6; + unsigned long epic_data7; +}; +#endif /* CONFIG_ALPHA_MIKASA */ + +struct el_procdata { + unsigned long paltemp[32]; /* PAL TEMP REGS. */ + /* EV4-specific fields */ + unsigned long exc_addr; /* Address of excepting instruction. */ + unsigned long exc_sum; /* Summary of arithmetic traps. */ + unsigned long exc_mask; /* Exception mask (from exc_sum). */ + unsigned long iccsr; /* IBox hardware enables. */ + unsigned long pal_base; /* Base address for PALcode. */ + unsigned long hier; /* Hardware Interrupt Enable. */ + unsigned long hirr; /* Hardware Interrupt Request. */ + unsigned long csr; /* D-stream fault info. */ + unsigned long dc_stat; /* D-cache status (ECC/Parity Err). */ + unsigned long dc_addr; /* EV3 Phys Addr for ECC/DPERR. */ + unsigned long abox_ctl; /* ABox Control Register. */ + unsigned long biu_stat; /* BIU Status. */ + unsigned long biu_addr; /* BUI Address. */ + unsigned long biu_ctl; /* BIU Control. */ + unsigned long fill_syndrome;/* For correcting ECC errors. */ + unsigned long fill_addr; /* Cache block which was being read */ + unsigned long va; /* Effective VA of fault or miss. */ + unsigned long bc_tag; /* Backup Cache Tag Probe Results.*/ +}; + #define RTC_PORT(x) (0x70 + (x)) #define RTC_ADDR(x) (0x80 | (x)) diff -ur --new-file old/linux/include/asm-alpha/byteorder.h new/linux/include/asm-alpha/byteorder.h --- old/linux/include/asm-alpha/byteorder.h Thu Feb 15 08:20:41 1996 +++ new/linux/include/asm-alpha/byteorder.h Mon Jul 1 19:06:05 1996 @@ -21,6 +21,9 @@ extern unsigned long int __ntohl(unsigned long int); extern unsigned short int __ntohs(unsigned short int); + +#ifdef __GNUC__ + extern unsigned long int __constant_ntohl(unsigned long int); extern unsigned short int __constant_ntohs(unsigned short int); @@ -100,6 +103,8 @@ (__builtin_constant_p((short)(x)) ? \ __constant_htons((x)) : \ __htons((x))) -#endif +#endif /* __OPTIMIZE__ */ + +#endif /* __GNUC__ */ -#endif +#endif /* _ALPHA_BYTEORDER_H */ diff -ur --new-file old/linux/include/asm-alpha/cia.h new/linux/include/asm-alpha/cia.h --- old/linux/include/asm-alpha/cia.h Tue Jun 4 05:06:38 1996 +++ new/linux/include/asm-alpha/cia.h Mon Jul 15 10:34:11 1996 @@ -1,6 +1,7 @@ #ifndef __ALPHA_CIA__H__ #define __ALPHA_CIA__H__ +#include #include /* @@ -169,6 +170,14 @@ #define GRU_SCR (IDENT_ADDR + 0x8780000300UL) #define GRU_LED (IDENT_ADDR + 0x8780000800UL) #define GRU_RESET (IDENT_ADDR + 0x8780000900UL) + +#if defined(CONFIG_ALPHA_ALCOR) +#define GRU_INT_REQ_BITS 0x800fffffUL +#elif defined(CONFIG_ALPHA_XLT) +#define GRU_INT_REQ_BITS 0x80003fffUL +#else +#define GRU_INT_REQ_BITS 0xffffffffUL +#endif /* * Bit definitions for I/O Controller status register 0: diff -ur --new-file old/linux/include/asm-alpha/elf.h new/linux/include/asm-alpha/elf.h --- old/linux/include/asm-alpha/elf.h Wed Jul 5 11:53:22 1995 +++ new/linux/include/asm-alpha/elf.h Sun Aug 18 09:37:57 1996 @@ -5,7 +5,12 @@ * ELF register definitions.. */ -#define ELF_NGREG 32 +/* + * The OSF/1 version of makes gregset_t 46 entries long. + * I have no idea why that is so. For now, we just leave it at 33 + * (32 general regs + processor status word). + */ +#define ELF_NGREG 33 #define ELF_NFPREG 32 typedef unsigned long elf_greg_t; @@ -13,5 +18,77 @@ typedef double elf_fpreg_t; typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; + +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch(x) ((x) == EM_ALPHA) + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS64 +#define ELF_DATA ELFDATA2LSB; +#define ELF_ARCH EM_ALPHA + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 8192 + +/* $0 is set by ld.so to a pointer to a function which might be + registered using atexit. This provides a mean for the dynamic + linker to call DT_FINI functions for shared libraries that have + been loaded before the code runs. + + So that we can use the same startup file with static executables, + we start programs with a value of 0 to indicate that there is no + such function. */ + +#define ELF_PLAT_INIT(_r) _r->r0 = 0 + +/* Use the same format as the OSF/1 procfs interface. The register + layout is sane. However, since dump_thread() creates the funky + layout that ECOFF coredumps want, we need to undo that layout here. + Eventually, it would be nice if the ECOFF core-dump had to do the + translation, then ELF_CORE_COPY_REGS() would become trivial and + faster. */ +#define ELF_CORE_COPY_REGS(_dest,_regs) \ +{ \ + struct user _dump; \ + \ + dump_thread(_regs, &_dump); \ + _dest[ 0] = _dump.regs[EF_V0]; \ + _dest[ 1] = _dump.regs[EF_T0]; \ + _dest[ 2] = _dump.regs[EF_T1]; \ + _dest[ 3] = _dump.regs[EF_T2]; \ + _dest[ 4] = _dump.regs[EF_T3]; \ + _dest[ 5] = _dump.regs[EF_T4]; \ + _dest[ 6] = _dump.regs[EF_T5]; \ + _dest[ 7] = _dump.regs[EF_T6]; \ + _dest[ 8] = _dump.regs[EF_T7]; \ + _dest[ 9] = _dump.regs[EF_S0]; \ + _dest[10] = _dump.regs[EF_S1]; \ + _dest[11] = _dump.regs[EF_S2]; \ + _dest[12] = _dump.regs[EF_S3]; \ + _dest[13] = _dump.regs[EF_S4]; \ + _dest[14] = _dump.regs[EF_S5]; \ + _dest[15] = _dump.regs[EF_S6]; \ + _dest[16] = _dump.regs[EF_A0]; \ + _dest[17] = _dump.regs[EF_A1]; \ + _dest[18] = _dump.regs[EF_A2]; \ + _dest[19] = _dump.regs[EF_A3]; \ + _dest[20] = _dump.regs[EF_A4]; \ + _dest[21] = _dump.regs[EF_A5]; \ + _dest[22] = _dump.regs[EF_T8]; \ + _dest[23] = _dump.regs[EF_T9]; \ + _dest[24] = _dump.regs[EF_T10]; \ + _dest[25] = _dump.regs[EF_T11]; \ + _dest[26] = _dump.regs[EF_RA]; \ + _dest[27] = _dump.regs[EF_T12]; \ + _dest[28] = _dump.regs[EF_AT]; \ + _dest[29] = _dump.regs[EF_GP]; \ + _dest[30] = _dump.regs[EF_SP]; \ + _dest[31] = _dump.regs[EF_PC]; /* store PC here */ \ + _dest[32] = _dump.regs[EF_PS]; \ +} #endif diff -ur --new-file old/linux/include/asm-alpha/errno.h new/linux/include/asm-alpha/errno.h --- old/linux/include/asm-alpha/errno.h Tue Nov 7 08:18:35 1995 +++ new/linux/include/asm-alpha/errno.h Thu Jul 4 06:28:57 1996 @@ -106,7 +106,9 @@ #define ENOANO 100 /* No anode */ #define EBADRQC 101 /* Invalid request code */ #define EBADSLT 102 /* Invalid slot */ -#define EDEADLOCK 103 /* File locking deadlock error */ + +#define EDEADLOCK EDEADLK + #define EBFONT 104 /* Bad font file format */ #define ENONET 105 /* Machine is not on the network */ #define ENOLINK 106 /* Link has been severed */ diff -ur --new-file old/linux/include/asm-alpha/fcntl.h new/linux/include/asm-alpha/fcntl.h --- old/linux/include/asm-alpha/fcntl.h Tue Apr 30 12:09:45 1996 +++ new/linux/include/asm-alpha/fcntl.h Sun Aug 4 12:39:07 1996 @@ -58,9 +58,9 @@ struct flock { short l_type; short l_whence; - off_t l_start; - off_t l_len; - pid_t l_pid; + __kernel_off_t l_start; + __kernel_off_t l_len; + __kernel_pid_t l_pid; }; #endif diff -ur --new-file old/linux/include/asm-alpha/irq.h new/linux/include/asm-alpha/irq.h --- old/linux/include/asm-alpha/irq.h Tue Jun 4 05:06:38 1996 +++ new/linux/include/asm-alpha/irq.h Mon Jul 15 08:47:42 1996 @@ -14,7 +14,7 @@ # define NR_IRQS 33 #elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P) || defined(CONFIG_ALPHA_MIKASA) # define NR_IRQS 32 -#elif defined(CONFIG_ALPHA_ALCOR) +#elif defined(CONFIG_ALPHA_ALCOR) || defined(CONFIG_ALPHA_XLT) # define NR_IRQS 48 #else # define NR_IRQS 16 diff -ur --new-file old/linux/include/asm-alpha/posix_types.h new/linux/include/asm-alpha/posix_types.h --- old/linux/include/asm-alpha/posix_types.h Thu Apr 4 16:05:01 1996 +++ new/linux/include/asm-alpha/posix_types.h Sun Aug 4 12:39:07 1996 @@ -22,6 +22,7 @@ typedef long __kernel_clock_t; typedef int __kernel_daddr_t; typedef char * __kernel_caddr_t; +typedef unsigned long __kernel_sigset_t; /* at least 32 bits */ #ifdef __GNUC__ typedef long long __kernel_loff_t; @@ -60,7 +61,7 @@ } #undef __FD_ISSET -static __inline__ int __FD_ISSET(unsigned long fd, __kernel_fd_set *p) +static __inline__ int __FD_ISSET(unsigned long fd, const __kernel_fd_set *p) { unsigned long _tmp = fd / __NFDBITS; unsigned long _rem = fd % __NFDBITS; @@ -74,18 +75,29 @@ #undef __FD_ZERO static __inline__ void __FD_ZERO(__kernel_fd_set *p) { - unsigned int *tmp = p->fds_bits; + unsigned long *tmp = p->fds_bits; int i; - if (__builtin_constant_p(__FDSET_INTS)) { - switch (__FDSET_INTS) { - case 8: - tmp[0] = 0; tmp[1] = 0; tmp[2] = 0; tmp[3] = 0; - tmp[4] = 0; tmp[5] = 0; tmp[6] = 0; tmp[7] = 0; - return; + if (__builtin_constant_p(__FDSET_LONGS)) { + switch (__FDSET_LONGS) { + case 16: + tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0; + tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0; + tmp[ 8] = 0; tmp[ 9] = 0; tmp[10] = 0; tmp[11] = 0; + tmp[12] = 0; tmp[13] = 0; tmp[14] = 0; tmp[15] = 0; + return; + + case 8: + tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0; + tmp[ 4] = 0; tmp[ 5] = 0; tmp[ 6] = 0; tmp[ 7] = 0; + return; + + case 4: + tmp[ 0] = 0; tmp[ 1] = 0; tmp[ 2] = 0; tmp[ 3] = 0; + return; } } - i = __FDSET_INTS; + i = __FDSET_LONGS; while (i) { i--; *tmp = 0; diff -ur --new-file old/linux/include/asm-alpha/processor.h new/linux/include/asm-alpha/processor.h --- old/linux/include/asm-alpha/processor.h Fri Dec 22 07:22:06 1995 +++ new/linux/include/asm-alpha/processor.h Sun Aug 18 09:37:57 1996 @@ -27,6 +27,7 @@ #define wp_works_ok__is_a_macro /* for versions in ksyms.c */ struct thread_struct { + /* the fields below are used by PALcode and must match struct pcb: */ unsigned long ksp; unsigned long usp; unsigned long ptbr; @@ -34,11 +35,18 @@ unsigned int asn; unsigned long unique; /* - * bit 0.. 0: floating point enable (used by PALcode) - * bit 1.. 5: IEEE_TRAP_ENABLE bits (see fpu.h) + * bit 0: floating point enable + * bit 62: performance monitor enable */ - unsigned long flags; + unsigned long pal_flags; unsigned long res1, res2; + + /* the fields below are Linux-specific: */ + /* + * bit 0: perform syscall argument validation (get/set_fs) + * bit 1..5: IEEE_TRAP_ENABLE bits (see fpu.h) + */ + unsigned long flags; }; #define INIT_MMAP { &init_mm, 0xfffffc0000000000, 0xfffffc0010000000, \ @@ -48,6 +56,7 @@ 0, 0, 0, \ 0, 0, 0, \ 0, 0, 0, \ + 0 \ } #define alloc_kernel_stack() get_free_page(GFP_KERNEL) @@ -74,11 +83,6 @@ /* * Do necessary setup to start up a newly executed thread. */ -static inline void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp) -{ - regs->pc = pc; - regs->ps = 8; - wrusp(sp); -} +extern void start_thread(struct pt_regs *, unsigned long, unsigned long); #endif /* __ASM_ALPHA_PROCESSOR_H */ diff -ur --new-file old/linux/include/asm-alpha/segment.h new/linux/include/asm-alpha/segment.h --- old/linux/include/asm-alpha/segment.h Sat Nov 25 10:54:56 1995 +++ new/linux/include/asm-alpha/segment.h Sun Aug 18 09:37:57 1996 @@ -102,27 +102,22 @@ } /* - * For segmented architectures, these are used to specify which segment - * to use for the above functions. + * The fs value determines whether argument validity checking should be + * performed or not. If get_fs() == USER_DS, checking is performed, with + * get_fs() == KERNEL_DS, checking is bypassed. * - * The alpha is not segmented, so these are just dummies. + * For historical reasons, these macros are grossly misnamed. */ -#define KERNEL_DS 0 -#define USER_DS 1 +#define KERNEL_DS 0 +#define USER_DS 1 -static inline unsigned long get_fs(void) -{ - return 1; -} +#define get_fs() (current->tss.flags & 0x1) +#define set_fs(x) (current->tss.flags = (current->tss.flags & ~0x1) | ((x) & 0x1)) static inline unsigned long get_ds(void) { return 0; -} - -static inline void set_fs(unsigned long val) -{ } #endif /* _ASM_SEGMENT_H */ diff -ur --new-file old/linux/include/asm-alpha/statfs.h new/linux/include/asm-alpha/statfs.h --- old/linux/include/asm-alpha/statfs.h Sat Jun 1 08:33:54 1996 +++ new/linux/include/asm-alpha/statfs.h Sun Aug 18 09:42:02 1996 @@ -3,29 +3,23 @@ #ifndef __KERNEL_STRICT_NAMES -#include +#include typedef __kernel_fsid_t fsid_t; #endif -/* - * The OSF/1 statfs structure is much larger, but this should - * match the beginning, at least. - */ struct statfs { - short f_type; - short f_flags; - int f_fsize; - int f_bsize; - int f_blocks; - int f_bfree; - int f_bavail; - int f_files; - int f_ffree; + int f_type; + int f_bsize; + int f_blocks; + int f_bfree; + int f_bavail; + int f_files; + int f_ffree; __kernel_fsid_t f_fsid; - /* linux-specific entries start here.. */ - int f_namelen; + int f_namelen; + int f_spare[6]; }; #endif diff -ur --new-file old/linux/include/asm-alpha/system.h new/linux/include/asm-alpha/system.h --- old/linux/include/asm-alpha/system.h Sat Apr 20 11:58:38 1996 +++ new/linux/include/asm-alpha/system.h Sun Aug 4 12:37:59 1996 @@ -17,6 +17,7 @@ */ #define BOOT_PCB 0x20000000 #define BOOT_ADDR 0x20000000 +/* Remove when official MILO sources have ELF support: */ #define BOOT_SIZE (16*1024) #define KERNEL_START 0xfffffc0000300000 @@ -27,6 +28,7 @@ #define ZERO_PGE 0xfffffc000030A000 #define START_ADDR 0xfffffc0000310000 +/* Remove when official MILO sources have ELF support: */ #define START_SIZE (2*1024*1024) #ifndef __ASSEMBLY__ diff -ur --new-file old/linux/include/asm-alpha/unistd.h new/linux/include/asm-alpha/unistd.h --- old/linux/include/asm-alpha/unistd.h Sat Jun 8 10:09:40 1996 +++ new/linux/include/asm-alpha/unistd.h Sun Aug 4 12:39:07 1996 @@ -165,53 +165,55 @@ #define __NR_uname 339 #define __NR_nanosleep 340 #define __NR_mremap 341 +#define __NR_nfsctl 342 -#ifdef __LIBRARY__ - -/* - * Duh, the alpha gcc compiler doesn't allow us to specify regs - * yet. I'll have to see about this later.. - */ +#if defined(__LIBRARY__) && defined(__GNUC__) /* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */ -#define _syscall0(type,name) \ -type name(void) \ -{ \ - return (type) -1; \ +#define _syscall0(type, name) \ +type name(void) \ +{ \ + extern long syscall (int, ...); \ + return syscall(__NR_##name)); \ } -#define _syscall1(type,name,type1,arg1) \ -type name(type1 arg1) \ -{ \ - return (type) -1; \ +#define _syscall1(type,name,type1,arg1) \ +type name(type1 arg1) \ +{ \ + extern long syscall (int, ...); \ + return syscall(__NR_##name, arg1); \ } -#define _syscall2(type,name,type1,arg1,type2,arg2) \ -type name(type1 arg1,type2 arg2) \ -{ \ - return (type) -1; \ +#define _syscall2(type,name,type1,arg1,type2,arg2) \ +type name(type1 arg1,type2 arg2) \ +{ \ + extern long syscall (int, ...); \ + return syscall(__NR_##name, arg1, arg2); \ } -#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ -type name(type1 arg1,type2 arg2,type3 arg3) \ -{ \ - return (type) -1; \ +#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ +type name(type1 arg1,type2 arg2,type3 arg3) \ +{ \ + extern long syscall (int, ...); \ + return syscall(__NR_##name, arg1, arg2, arg3); \ } #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ -type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \ -{ \ - return (type) -1; \ +type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \ +{ \ + extern long syscall (int, ...); \ + return syscall(__NR_##name, arg1, arg2, arg3, arg4); \ } #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ - type5,arg5) \ -type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \ -{ \ - return (type) -1; \ + type5,arg5) \ +type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \ +{ \ + extern long syscall (int, ...); \ + return syscall(__NR_##name, arg1, arg2, arg3, arg4); \ } -#endif /* __LIBRARY__ */ +#endif /* __LIBRARY__ && __GNUC__ */ #ifdef __KERNEL_SYSCALLS__ diff -ur --new-file old/linux/include/asm-i386/elf.h new/linux/include/asm-i386/elf.h --- old/linux/include/asm-i386/elf.h Wed Jul 5 11:53:22 1995 +++ new/linux/include/asm-i386/elf.h Sun Aug 4 13:12:40 1996 @@ -14,4 +14,28 @@ typedef struct user_i387_struct elf_fpregset_t; +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch(x) ( ((x) == EM_386) || ((x) == EM_486) ) + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2LSB; +#define ELF_ARCH EM_386 + + /* SVR4/i386 ABI (pages 3-31, 3-32) says that when the program + starts %edx contains a pointer to a function which might be + registered using `atexit'. This provides a mean for the + dynamic linker to call DT_FINI functions for shared libraries + that have been loaded before the code runs. + + A value of 0 tells we have no such handler. */ +#define ELF_PLAT_INIT(_r) _r->edx = 0 + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + #endif diff -ur --new-file old/linux/include/asm-i386/errno.h new/linux/include/asm-i386/errno.h --- old/linux/include/asm-i386/errno.h Sat Jun 10 17:36:48 1995 +++ new/linux/include/asm-i386/errno.h Thu Jul 4 06:28:57 1996 @@ -58,7 +58,9 @@ #define ENOANO 55 /* No anode */ #define EBADRQC 56 /* Invalid request code */ #define EBADSLT 57 /* Invalid slot */ -#define EDEADLOCK 58 /* File locking deadlock error */ + +#define EDEADLOCK EDEADLK + #define EBFONT 59 /* Bad font file format */ #define ENOSTR 60 /* Device not a stream */ #define ENODATA 61 /* No data available */ diff -ur --new-file old/linux/include/asm-i386/pgtable.h new/linux/include/asm-i386/pgtable.h --- old/linux/include/asm-i386/pgtable.h Tue Apr 23 12:41:25 1996 +++ new/linux/include/asm-i386/pgtable.h Wed Jul 17 09:35:40 1996 @@ -293,14 +293,14 @@ __asm__ __volatile__("movl %0,%%cr3": :"r" (pgdir)); \ } while (0) -extern inline int pte_none(pte_t pte) { return !pte_val(pte); } -extern inline int pte_present(pte_t pte) { return pte_val(pte) & _PAGE_PRESENT; } -extern inline void pte_clear(pte_t *ptep) { pte_val(*ptep) = 0; } - -extern inline int pmd_none(pmd_t pmd) { return !pmd_val(pmd); } -extern inline int pmd_bad(pmd_t pmd) { return (pmd_val(pmd) & ~PAGE_MASK) != _PAGE_TABLE || pmd_val(pmd) > high_memory; } -extern inline int pmd_present(pmd_t pmd) { return pmd_val(pmd) & _PAGE_PRESENT; } -extern inline void pmd_clear(pmd_t * pmdp) { pmd_val(*pmdp) = 0; } +#define pte_none(x) (!pte_val(x)) +#define pte_present(x) (pte_val(x) & _PAGE_PRESENT) +#define pte_clear(xp) do { pte_val(*(xp)) = 0; } while (0) + +#define pmd_none(x) (!pmd_val(x)) +#define pmd_bad(x) ((pmd_val(x) & ~PAGE_MASK) != _PAGE_TABLE) +#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT) +#define pmd_clear(xp) do { pmd_val(*(xp)) = 0; } while (0) /* * The "pgd_xxx()" functions here are trivial for a folded two-level @@ -421,25 +421,35 @@ extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address) { - address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); - if (pmd_none(*pmd)) { - pte_t * page = (pte_t *) get_free_page(GFP_KERNEL); - if (pmd_none(*pmd)) { - if (page) { - pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) page; - return page + address; - } - pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE; - return NULL; - } - free_page((unsigned long) page); - } - if (pmd_bad(*pmd)) { - printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); - pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE; - return NULL; - } - return (pte_t *) pmd_page(*pmd) + address; + address = (address >> (PAGE_SHIFT-2)) & 4*(PTRS_PER_PTE - 1); + +repeat: + if (pmd_none(*pmd)) + goto getnew; + if (pmd_bad(*pmd)) + goto fix; + return (pte_t *) (pmd_page(*pmd) + address); + +getnew: +{ + unsigned long page = __get_free_page(GFP_KERNEL); + if (!pmd_none(*pmd)) + goto freenew; + if (!page) + goto oom; + memset((void *) page, 0, PAGE_SIZE); + pmd_val(*pmd) = _PAGE_TABLE | page; + return (pte_t *) (page + address); +freenew: + free_page(page); + goto repeat; +} + +fix: + printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd)); +oom: + pmd_val(*pmd) = _PAGE_TABLE | (unsigned long) BAD_PAGETABLE; + return NULL; } /* diff -ur --new-file old/linux/include/asm-i386/posix_types.h new/linux/include/asm-i386/posix_types.h --- old/linux/include/asm-i386/posix_types.h Mon Jun 3 09:09:13 1996 +++ new/linux/include/asm-i386/posix_types.h Sat Jul 6 10:14:34 1996 @@ -28,32 +28,36 @@ #endif typedef struct { +#if defined(__KERNEL__) || defined(__USE_ALL) int val[2]; +#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */ + int __val[2]; +#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */ } __kernel_fsid_t; #undef __FD_SET #define __FD_SET(fd,fdsetp) \ __asm__ __volatile__("btsl %1,%0": \ - "=m" (*(fd_set *) (fdsetp)):"r" ((int) (fd))) + "=m" (*(__kernel_fd_set *) (fdsetp)):"r" ((int) (fd))) #undef __FD_CLR #define __FD_CLR(fd,fdsetp) \ __asm__ __volatile__("btrl %1,%0": \ - "=m" (*(fd_set *) (fdsetp)):"r" ((int) (fd))) + "=m" (*(__kernel_fd_set *) (fdsetp)):"r" ((int) (fd))) #undef __FD_ISSET #define __FD_ISSET(fd,fdsetp) (__extension__ ({ \ unsigned char __result; \ __asm__ __volatile__("btl %1,%2 ; setb %0" \ :"=q" (__result) :"r" ((int) (fd)), \ - "m" (*(fd_set *) (fdsetp))); \ + "m" (*(__kernel_fd_set *) (fdsetp))); \ __result; })) #undef __FD_ZERO #define __FD_ZERO(fdsetp) \ __asm__ __volatile__("cld ; rep ; stosl" \ - :"=m" (*(fd_set *) (fdsetp)) \ - :"a" (0), "c" (__FDSET_INTS), \ - "D" ((fd_set *) (fdsetp)) :"cx","di") + :"=m" (*(__kernel_fd_set *) (fdsetp)) \ + :"a" (0), "c" (__FDSET_LONGS), \ + "D" ((__kernel_fd_set *) (fdsetp)) :"cx","di") #endif diff -ur --new-file old/linux/include/asm-i386/system.h new/linux/include/asm-i386/system.h --- old/linux/include/asm-i386/system.h Wed May 29 17:06:39 1996 +++ new/linux/include/asm-i386/system.h Thu Aug 1 14:43:04 1996 @@ -5,11 +5,12 @@ /* * Entry into gdt where to find first TSS. GDT layout: - * 0 - nul - * 1 - kernel code segment - * 2 - kernel data segment - * 3 - user code segment - * 4 - user data segment + * 0 - null + * 1 - not used + * 2 - kernel code segment + * 3 - kernel data segment + * 4 - user code segment + * 5 - user data segment * ... * 8 - TSS #0 * 9 - LDT #0 diff -ur --new-file old/linux/include/asm-m68k/elf.h new/linux/include/asm-m68k/elf.h --- old/linux/include/asm-m68k/elf.h Mon May 6 11:44:32 1996 +++ new/linux/include/asm-m68k/elf.h Thu Aug 8 11:25:46 1996 @@ -14,4 +14,49 @@ typedef struct user_m68kfp_struct elf_fpregset_t; +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch(x) ((x) == EM_68K) + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2MSB; +#define ELF_ARCH EM_68K + + /* For SVR4/m68k the function pointer to be registered with + `atexit' is passed in %a1. Although my copy of the ABI has + no such statement, it is actually used on ASV. */ +#define ELF_PLAT_INIT(_r) _r->a1 = 0 + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +#define ELF_CORE_COPY_REGS(pr_reg, regs) \ + /* Bleech. */ \ + pr_reg[0] = regs->d1; \ + pr_reg[1] = regs->d2; \ + pr_reg[2] = regs->d3; \ + pr_reg[3] = regs->d4; \ + pr_reg[4] = regs->d5; \ + pr_reg[7] = regs->a0; \ + pr_reg[8] = regs->a1; \ + pr_reg[14] = regs->d0; \ + pr_reg[15] = rdusp(); \ + pr_reg[16] = 0; /* orig_d0 */ \ + pr_reg[17] = regs->sr; \ + pr_reg[18] = regs->pc; \ + { \ + struct switch_stack *sw = ((struct switch_stack *)regs) - 1; \ + pr_reg[5] = sw->d6; \ + pr_reg[6] = sw->d7; \ + pr_reg[9] = sw->a2; \ + pr_reg[10] = sw->a3; \ + pr_reg[11] = sw->a4; \ + pr_reg[12] = sw->a5; \ + pr_reg[13] = sw->a6; \ + } + #endif diff -ur --new-file old/linux/include/asm-m68k/ide.h new/linux/include/asm-m68k/ide.h --- old/linux/include/asm-m68k/ide.h Mon Apr 8 23:13:55 1996 +++ new/linux/include/asm-m68k/ide.h Tue Jul 23 10:33:32 1996 @@ -62,6 +62,31 @@ #undef HD_DATA #define HD_DATA NULL +/* MSch: changed sti() to STI() wherever possible in ide.c; moved STI() def. + * to asm/ide.h + */ +/* The Atari interrupt structure strictly requires that the IPL isn't lowered + * uncontrolled in an interrupt handler. In the concrete case, the IDE + * interrupt is already a slow int, so the irq is already disabled at the time + * the handler is called, and the IPL has been lowered to the minimum value + * possible. To avoid going below that, STI() checks for being called inside + * an interrupt, and in that case it does nothing. Hope that is reasonable and + * works. (Roman) + */ +#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) +#define STI() \ + do { \ + if (!intr_count) sti(); \ + } while(0) +#elif defined(CONFIG_ATARI) +#define STI() \ + do { \ + if (!MACH_IS_ATARI || !intr_count) sti(); \ + } while(0) +#else /* !defined(CONFIG_ATARI) */ +#define STI() sti() +#endif + #define SELECT_DRIVE(hwif,drive) OUT_BYTE((drive)->select.all, hwif->io_base+IDE_SELECT_OFFSET); #define insl(data_reg, buffer, wcount) insw(data_reg, buffer, wcount<<1) diff -ur --new-file old/linux/include/asm-mips/elf.h new/linux/include/asm-mips/elf.h --- old/linux/include/asm-mips/elf.h Wed Dec 13 11:39:45 1995 +++ new/linux/include/asm-mips/elf.h Sun Aug 4 13:12:40 1996 @@ -14,4 +14,20 @@ typedef double elf_fpreg_t; typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch(x) ((x) == EM_MIPS) + +/* + * These are used to set parameters in the core dumps. + * FIXME(eric) I don't know what the correct endianness to use is. + */ +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2MSB; +#define ELF_ARCH EM_MIPS + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + #endif /* __ASM_MIPS_ELF_H */ diff -ur --new-file old/linux/include/asm-ppc/elf.h new/linux/include/asm-ppc/elf.h --- old/linux/include/asm-ppc/elf.h Sat Nov 25 18:49:06 1995 +++ new/linux/include/asm-ppc/elf.h Sun Aug 4 13:12:40 1996 @@ -14,4 +14,17 @@ typedef double elf_fpreg_t; typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; +#define elf_check_arch(x) ((x) == EM_PPC) + +/* + * These are used to set parameters in the core dumps. + * FIXME(eric) I don't know what the correct endianness to use is. + */ +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2LSB; +#define ELF_ARCH EM_PPC + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + #endif diff -ur --new-file old/linux/include/asm-ppc/posix_types.h new/linux/include/asm-ppc/posix_types.h --- old/linux/include/asm-ppc/posix_types.h Tue May 28 06:46:04 1996 +++ new/linux/include/asm-ppc/posix_types.h Mon Jul 8 13:19:04 1996 @@ -77,15 +77,15 @@ unsigned int *tmp = p->fds_bits; int i; - if (__builtin_constant_p(__FDSET_INTS)) { - switch (__FDSET_INTS) { + if (__builtin_constant_p(__FDSET_LONGS)) { + switch (__FDSET_LONGS) { case 8: tmp[0] = 0; tmp[1] = 0; tmp[2] = 0; tmp[3] = 0; tmp[4] = 0; tmp[5] = 0; tmp[6] = 0; tmp[7] = 0; return; } } - i = __FDSET_INTS; + i = __FDSET_LONGS; while (i) { i--; *tmp = 0; diff -ur --new-file old/linux/include/asm-ppc/ppc_machine.h new/linux/include/asm-ppc/ppc_machine.h --- old/linux/include/asm-ppc/ppc_machine.h Thu Jan 1 01:00:00 1970 +++ new/linux/include/asm-ppc/ppc_machine.h Mon Jul 8 10:27:43 1996 @@ -0,0 +1,50 @@ +/* + * PowerPC machine specifics + */ + +#ifndef _PPC_MACHINE_H_ +#define _PPC_MACHINE_H_ + +/* Bit encodings for Machine State Register (MSR) */ +#define MSR_POW (1<<18) /* Enable Power Management */ +#define MSR_TGPR (1<<17) /* TLB Update registers in use */ +#define MSR_ILE (1<<16) /* Interrupt Little-Endian enable */ +#define MSR_EE (1<<15) /* External Interrupt enable */ +#define MSR_PR (1<<14) /* Supervisor/User privilege */ +#define MSR_FP (1<<13) /* Floating Point enable */ +#define MSR_ME (1<<12) /* Machine Check enable */ +#define MSR_FE0 (1<<11) /* Floating Exception mode 0 */ +#define MSR_SE (1<<10) /* Single Step */ +#define MSR_BE (1<<9) /* Branch Trace */ +#define MSR_FE1 (1<<8) /* Floating Exception mode 1 */ +#define MSR_IP (1<<6) /* Exception prefix 0x000/0xFFF */ +#define MSR_IR (1<<5) /* Instruction MMU enable */ +#define MSR_DR (1<<4) /* Data MMU enable */ +#define MSR_RI (1<<1) /* Recoverable Exception */ +#define MSR_LE (1<<0) /* Little-Endian enable */ + +#define MSR_ MSR_FP|MSR_FE0|MSR_FE1|MSR_ME +#define MSR_USER MSR_|MSR_PR|MSR_EE|MSR_IR|MSR_DR + +/* Bit encodings for Hardware Implementation Register (HID0) */ +#define HID0_EMCP (1<<31) /* Enable Machine Check pin */ +#define HID0_EBA (1<<29) /* Enable Bus Address Parity */ +#define HID0_EBD (1<<28) /* Enable Bus Data Parity */ +#define HID0_SBCLK (1<<27) +#define HID0_EICE (1<<26) +#define HID0_ECLK (1<<25) +#define HID0_PAR (1<<24) +#define HID0_DOZE (1<<23) +#define HID0_NAP (1<<22) +#define HID0_SLEEP (1<<21) +#define HID0_DPM (1<<20) +#define HID0_ICE (1<<15) /* Instruction Cache Enable */ +#define HID0_DCE (1<<14) /* Data Cache Enable */ +#define HID0_ILOCK (1<<13) /* Instruction Cache Lock */ +#define HID0_DLOCK (1<<12) /* Data Cache Lock */ +#define HID0_ICFI (1<<11) /* Instruction Cache Flash Invalidate */ +#define HID0_DCI (1<<10) /* Data Cache Invalidate */ +#define HID0_SIED (1<<7) /* Serial Instruction Execution [Disable] */ +#define HID0_BHTE (1<<2) /* Branch History Table Enable */ + +#endif diff -ur --new-file old/linux/include/asm-ppc/unaligned.h new/linux/include/asm-ppc/unaligned.h --- old/linux/include/asm-ppc/unaligned.h Thu Jan 1 01:00:00 1970 +++ new/linux/include/asm-ppc/unaligned.h Mon Jul 8 10:27:43 1996 @@ -0,0 +1,16 @@ +#ifndef __PPC_UNALIGNED_H +#define __PPC_UNALIGNED_H + +/* + * The PowerPC can do unaligned accesses itself in big endian mode. + * + * The strange macros are there to make sure these can't + * be misused in a way that makes them not work on other + * architectures where unaligned accesses aren't as simple. + */ + +#define get_unaligned(ptr) (*(ptr)) + +#define put_unaligned(val, ptr) ((void)( *(ptr) = (val) )) + +#endif diff -ur --new-file old/linux/include/asm-ppc/unistd.h new/linux/include/asm-ppc/unistd.h --- old/linux/include/asm-ppc/unistd.h Mon May 27 11:00:59 1996 +++ new/linux/include/asm-ppc/unistd.h Mon Jul 8 10:27:43 1996 @@ -1,4 +1,3 @@ -/* * Last edited: Nov 17 16:28 1995 (cort) */ #ifndef _ASM_PPC_UNISTD_H_ #define _ASM_PPC_UNISTD_H_ @@ -154,97 +153,145 @@ #define __NR__newselect 142 #define __NR_flock 143 #define __NR_msync 144 -/*#define __NR_kclone 145*/ +#define __NR_readv 145 +#define __NR_writev 146 +#define __NR_getsid 147 + +#define __NR_mlock 150 +#define __NR_munlock 151 +#define __NR_mlockall 152 +#define __NR_munlockall 153 -/* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */ #define _syscall0(type,name) \ type name(void) \ { \ - __asm__ (_lisc(__NR_##name)); \ - __asm__ ("sc"); \ - __asm__ ("mr 31,3"); \ - __asm__ ("bns 10f"); \ - __asm__ ("mr 0,3"); \ - __asm__ ("lis 3,errno@ha"); \ - __asm__ ("stw 0,errno@l(3)"); \ - __asm__ ("li 3,-1"); \ - __asm__ ("10:"); \ + long retval; \ + __asm__ ( \ + "li 0, %0 \n\t" \ + "sc \n\t" \ + "mr 31,3 \n\t" \ + "bns 10f \n\t" \ + "mr 0,3 \n\t" \ + "lis 3,errno@ha \n\t" \ + "stw 0,errno@l(3) \n\t" \ + "li 3,-1 \n\t" \ + "10: \n\t" \ + : \ + : "i" (__NR_##name) \ + : "0", "31", "3", "cc", "memory" \ + ); \ + return(retval);\ } #define _syscall1(type,name,type1,arg1) \ type name(type1 arg1) \ { \ - __asm__ (_lisc(__NR_##name)); \ - __asm__ ("sc"); \ - __asm__ ("mr 31,3"); \ - __asm__ ("bns 10f"); \ - __asm__ ("mr 0,3"); \ - __asm__ ("lis 3,errno@ha"); \ - __asm__ ("stw 0,errno@l(3)"); \ - __asm__ ("li 3,-1"); \ - __asm__ ("10:"); \ + long retval; \ + __asm__ ( \ + "li 0, %0 \n\t" \ + "sc \n\t" \ + "mr 31,3 \n\t" \ + "bns 10f \n\t" \ + "mr 0,3 \n\t" \ + "lis 3,errno@ha \n\t" \ + "stw 0,errno@l(3) \n\t" \ + "li 3,-1 \n\t" \ + "10: \n\t" \ + : \ + : "i" (__NR_##name) \ + : "0", "31", "3", "cc", "memory" \ + ); \ + return(retval); \ } #define _syscall2(type,name,type1,arg1,type2,arg2) \ type name(type1 arg1,type2 arg2) \ { \ - __asm__ (_lisc(__NR_##name)); \ - __asm__ ("sc"); \ - __asm__ ("mr 31,3"); \ - __asm__ ("bns 10f"); \ - __asm__ ("mr 0,3"); \ - __asm__ ("lis 3,errno@ha"); \ - __asm__ ("stw 0,errno@l(3)"); \ - __asm__ ("li 3,-1"); \ - __asm__ ("10:"); \ + long retval; \ + __asm__ ( \ + "li 0, %0 \n\t" \ + "sc \n\t" \ + "mr 31,3 \n\t" \ + "bns 10f \n\t" \ + "mr 0,3 \n\t" \ + "lis 3,errno@ha \n\t" \ + "stw 0,errno@l(3) \n\t" \ + "li 3,-1 \n\t" \ + "10: \n\t" \ + : \ + : "i" (__NR_##name) \ + : "0", "31", "3", "cc", "memory" \ + ); \ + return(retval); \ } + #define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ -type name(type1 arg1,type2 arg2,type3 arg3) \ +type name(type1 arg1,type2 arg2, type3 arg3) \ { \ - __asm__ (_lisc(__NR_##name)); \ - __asm__ ("sc"); \ - __asm__ ("mr 31,3"); \ - __asm__ ("bns 10f"); \ - __asm__ ("mr 0,3"); \ - __asm__ ("lis 3,errno@ha"); \ - __asm__ ("stw 0,errno@l(3)"); \ - __asm__ ("li 3,-1"); \ - __asm__ ("10:"); \ + long retval; \ + __asm__ ( \ + "li 0, %0 \n\t" \ + "sc \n\t" \ + "mr 31,3 \n\t" \ + "bns 10f \n\t" \ + "mr 0,3 \n\t" \ + "lis 3,errno@ha \n\t" \ + "stw 0,errno@l(3) \n\t" \ + "li 3,-1 \n\t" \ + "10: \n\t" \ + : \ + : "i" (__NR_##name) \ + : "0", "31", "3", "cc", "memory" \ + ); \ + return(retval); \ } #define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \ { \ - __asm__ (_lisc(__NR_##name)); \ - __asm__ ("sc"); \ - __asm__ ("mr 31,3"); \ - __asm__ ("bns 10f"); \ - __asm__ ("mr 0,3"); \ - __asm__ ("lis 3,errno@ha"); \ - __asm__ ("stw 0,errno@l(3)"); \ - __asm__ ("li 3,-1"); \ - __asm__ ("10:"); \ -} + long retval; \ + __asm__ ( \ + "li 0, %0 \n\t" \ + "sc \n\t" \ + "mr 31,3 \n\t" \ + "bns 10f \n\t" \ + "mr 0,3 \n\t" \ + "lis 3,errno@ha \n\t" \ + "stw 0,errno@l(3) \n\t" \ + "li 3,-1 \n\t" \ + "10: \n\t" \ + : \ + : "i" (__NR_##name) \ + : "0", "31", "3", "cc", "memory" \ + ); \ + return(retval); \ +} #define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ type5,arg5) \ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \ { \ - __asm__ (_lisc(__NR_##name)); \ - __asm__ ("sc"); \ - __asm__ ("mr 31,3"); \ - __asm__ ("bns 10f"); \ - __asm__ ("mr 0,3"); \ - __asm__ ("lis 3,errno@ha"); \ - __asm__ ("stw 0,errno@l(3)"); \ - __asm__ ("li 3,-1"); \ - __asm__ ("10:"); \ + long retval; \ + __asm__ ( \ + "li 0, %0 \n\t" \ + "sc \n\t" \ + "mr 31,3 \n\t" \ + "bns 10f \n\t" \ + "mr 0,3 \n\t" \ + "lis 3,errno@ha \n\t" \ + "stw 0,errno@l(3) \n\t" \ + "li 3,-1 \n\t" \ + "10: \n\t" \ + : \ + : "i" (__NR_##name) \ + : "0", "31", "3", "cc", "memory" \ + ); \ + return(retval); \ } #ifdef __KERNEL_SYSCALLS__ - /* * we need this inline - forking from kernel space will result * in NO COPY ON WRITE (!!!), until an execve is executed. This @@ -258,83 +305,72 @@ * some others too. */ -extern long __kernel_thread(unsigned long, int (*)(void *), void *); - -static inline long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) -{ - return __kernel_thread(flags | CLONE_VM, fn, arg); -} - /* some of these had problems getting the right arguments (namely sys_clone()) - when they were inline. + when they were inline so I made them non-inline until we get problems with gcc + worked out. I need to check with Linus to find out which he wants inline now + since the above comment was written a long time ago. + + Once I understand the macro language better this should go away. -- Cort */ -#define __NR__exit __NR_exit -static inline _syscall0(int,idle) /* made inline "just in case" -- Cort */ -static inline _syscall0(int,fork) /* needs to be inline */ -static inline _syscall0(int,pause) /* needs to be inline */ -static inline _syscall0(int,setup) /* called in init before execve */ -static inline _syscall0(int,sync) -static inline _syscall0(pid_t,setsid) -static /*inline*/ _syscall3(int,write,int,fd,const char *,buf,off_t,count) -static /*inline*/ _syscall1(int,dup,int,fd) -static /*inline*/ _syscall3(int,execve,const char *,file,char **,argv,char **,envp) -static /*inline*/ _syscall3(int,open,const char *,file,int,flag,int,mode) -static inline _syscall1(int,close,int,fd) -static /*inline*/ _syscall1(int,_exit,int,exitcode) -static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) -/*static inline _syscall2(int,clone,unsigned long,flags,char *,esp)*/ -/* - syscalls from kernel mode is a little strange and I can't get used to - the idea -- this makes me feel better. -- Cort - */ -/*static inline int kclone (void) -{ - __asm__ (_lisc(__NR_kclone)); - __asm__ ("sc"); - __asm__ ("mr 31,3"); - __asm__ ("bns 10f"); - __asm__ ("mr 0,3"); - __asm__ ("lis 3,errno@ha"); - __asm__ ("stw 0,errno@l(3)"); - __asm__ ("li 3,-1"); - __asm__ ("10:"); -}*/ +#define __NR__exit __NR_exit +static /*__inline__*/ _syscall0(int,setup) +static __inline__ _syscall0(int,idle) +static /*__inline__*/ _syscall0(int,fork) +static __inline__ _syscall0(int,pause) +static __inline__ _syscall0(int,sync) +static __inline__ _syscall0(pid_t,setsid) +static __inline__ _syscall3(int,write,int,fd,const char *,buf,off_t,count) +static /*__inline__*/ _syscall1(int,dup,int,fd) +static /*__inline__*/ _syscall3(int,execve,const char *,file,char **,argv,char **,envp) +static __inline__ _syscall3(int,open,const char *,file,int,flag,int,mode) +static /*__inline__*/ _syscall1(int,close,int,fd) +static /*__inline__*/ _syscall1(int,_exit,int,exitcode) +static __inline__ _syscall2(int,clone,unsigned long,flags,char *,esp) +static __inline__ _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) -static inline int clone (unsigned long flags,char *esp) +static __inline__ pid_t wait(int * wait_stat) { -/* printk("unistd.h: clone(): flags = %x, esp = %x\n", flags, esp);*/ - __asm__ (_lisc(__NR_clone)); - __asm__ ("sc"); - __asm__ ("mr 31,3"); - -/* this is a hack to get the damned thing to return something even though inlined - -- Cort - */ - __asm__ ("mr 0,3"); - __asm__ ("lis 3,errno@ha"); - __asm__ ("stw 0,errno@l(3)"); - - __asm__ ("bns 10f"); - __asm__ ("mr 0,3"); - __asm__ ("lis 3,errno@ha"); - __asm__ ("stw 0,errno@l(3)"); - __asm__ ("li 3,-1"); - __asm__ ("10:"); - return errno; + return waitpid(-1,wait_stat,0); } - -/* called from init before execve -- need to be inline? -- Cort */ -static inline pid_t wait(int * wait_stat) +/* + This is the mechanism for creating a new kernel thread. + For the time being it only behaves the same as clone(). + It should be changed very soon to work properly and cleanly. This + gets us going for now, though. + -- Cort + */ +static __inline__ long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { - return waitpid(-1,wait_stat,0); + long retval; + __asm__ ( + "li 0, 120 \n\t" /* __NR_clone */ + "li 3, %5 \n\t" /* load flags as arg to clone */ + /*"mr 1,7 \n\t"*/ /* save kernel stack */ + "sc \n\t" /* syscall */ + /*"cmp 0,1,7 \n\t"*/ /* if kernel stack changes -- child */ + "cmpi 0,3,0 \n\t" + "bne 1f \n\t" /* return if parent */ + /* this is in child */ + "li 3, %3 \n\t" /* child -- load args and call fn */ + "mtlr %4 \n\t" + "blrl \n\t" + "li 0, %2 \n\t" /* exit after child exits */ + "li 3, 0 \n\t" + "sc \n\t" + /* parent */ + "1: \n\t" + :"=3" (retval) + :"i" (__NR_clone), "i" (__NR_exit), + "r" (arg), "r" (fn), "g" (CLONE_VM|flags) + :"cc", "1", "0", "3", "7", "31", "memory" ); + return retval; } -#endif - -#endif /* _ASM_PPC_UNISTD_H_ */ +#endif /* __KERNEL_SYSCALLS__ */ +#endif /* _ASM_PPC_UNISTD_H_ */ diff -ur --new-file old/linux/include/asm-ppc/unistd.h.cort new/linux/include/asm-ppc/unistd.h.cort --- old/linux/include/asm-ppc/unistd.h.cort Thu Jan 1 01:00:00 1970 +++ new/linux/include/asm-ppc/unistd.h.cort Mon Jul 8 10:27:43 1996 @@ -0,0 +1,376 @@ +#ifndef _ASM_PPC_UNISTD_H_ +#define _ASM_PPC_UNISTD_H_ + +#define _NR(n) #n +#define _lisc(n) "li 0," _NR(n) + +/* + * This file contains the system call numbers. + */ + +#define __NR_setup 0 /* used only by init, to get system going */ +#define __NR_exit 1 +#define __NR_fork 2 +#define __NR_read 3 +#define __NR_write 4 +#define __NR_open 5 +#define __NR_close 6 +#define __NR_waitpid 7 +#define __NR_creat 8 +#define __NR_link 9 +#define __NR_unlink 10 +#define __NR_execve 11 +#define __NR_chdir 12 +#define __NR_time 13 +#define __NR_mknod 14 +#define __NR_chmod 15 +#define __NR_chown 16 +#define __NR_break 17 +#define __NR_oldstat 18 +#define __NR_lseek 19 +#define __NR_getpid 20 +#define __NR_mount 21 +#define __NR_umount 22 +#define __NR_setuid 23 +#define __NR_getuid 24 +#define __NR_stime 25 +#define __NR_ptrace 26 +#define __NR_alarm 27 +#define __NR_oldfstat 28 +#define __NR_pause 29 +#define __NR_utime 30 +#define __NR_stty 31 +#define __NR_gtty 32 +#define __NR_access 33 +#define __NR_nice 34 +#define __NR_ftime 35 +#define __NR_sync 36 +#define __NR_kill 37 +#define __NR_rename 38 +#define __NR_mkdir 39 +#define __NR_rmdir 40 +#define __NR_dup 41 +#define __NR_pipe 42 +#define __NR_times 43 +#define __NR_prof 44 +#define __NR_brk 45 +#define __NR_setgid 46 +#define __NR_getgid 47 +#define __NR_signal 48 +#define __NR_geteuid 49 +#define __NR_getegid 50 +#define __NR_acct 51 +#define __NR_phys 52 +#define __NR_lock 53 +#define __NR_ioctl 54 +#define __NR_fcntl 55 +#define __NR_mpx 56 +#define __NR_setpgid 57 +#define __NR_ulimit 58 +#define __NR_oldolduname 59 +#define __NR_umask 60 +#define __NR_chroot 61 +#define __NR_ustat 62 +#define __NR_dup2 63 +#define __NR_getppid 64 +#define __NR_getpgrp 65 +#define __NR_setsid 66 +#define __NR_sigaction 67 +#define __NR_sgetmask 68 +#define __NR_ssetmask 69 +#define __NR_setreuid 70 +#define __NR_setregid 71 +#define __NR_sigsuspend 72 +#define __NR_sigpending 73 +#define __NR_sethostname 74 +#define __NR_setrlimit 75 +#define __NR_getrlimit 76 +#define __NR_getrusage 77 +#define __NR_gettimeofday 78 +#define __NR_settimeofday 79 +#define __NR_getgroups 80 +#define __NR_setgroups 81 +#define __NR_select 82 +#define __NR_symlink 83 +#define __NR_oldlstat 84 +#define __NR_readlink 85 +#define __NR_uselib 86 +#define __NR_swapon 87 +#define __NR_reboot 88 +#define __NR_readdir 89 +#define __NR_mmap 90 +#define __NR_munmap 91 +#define __NR_truncate 92 +#define __NR_ftruncate 93 +#define __NR_fchmod 94 +#define __NR_fchown 95 +#define __NR_getpriority 96 +#define __NR_setpriority 97 +#define __NR_profil 98 +#define __NR_statfs 99 +#define __NR_fstatfs 100 +#define __NR_ioperm 101 +#define __NR_socketcall 102 +#define __NR_syslog 103 +#define __NR_setitimer 104 +#define __NR_getitimer 105 +#define __NR_stat 106 +#define __NR_lstat 107 +#define __NR_fstat 108 +#define __NR_olduname 109 +#define __NR_iopl 110 +#define __NR_vhangup 111 +#define __NR_idle 112 +#define __NR_vm86 113 +#define __NR_wait4 114 +#define __NR_swapoff 115 +#define __NR_sysinfo 116 +#define __NR_ipc 117 +#define __NR_fsync 118 +#define __NR_sigreturn 119 +#define __NR_clone 120 +#define __NR_setdomainname 121 +#define __NR_uname 122 +#define __NR_modify_ldt 123 +#define __NR_adjtimex 124 +#define __NR_mprotect 125 +#define __NR_sigprocmask 126 +#define __NR_create_module 127 +#define __NR_init_module 128 +#define __NR_delete_module 129 +#define __NR_get_kernel_syms 130 +#define __NR_quotactl 131 +#define __NR_getpgid 132 +#define __NR_fchdir 133 +#define __NR_bdflush 134 +#define __NR_sysfs 135 +#define __NR_personality 136 +#define __NR_afs_syscall 137 /* Syscall for Andrew File System */ +#define __NR_setfsuid 138 +#define __NR_setfsgid 139 +#define __NR__llseek 140 +#define __NR_getdents 141 +#define __NR__newselect 142 +#define __NR_flock 143 +#define __NR_msync 144 +#define __NR_readv 145 +#define __NR_writev 146 +#define __NR_getsid 147 + +#define __NR_mlock 150 +#define __NR_munlock 151 +#define __NR_mlockall 152 +#define __NR_munlockall 153 + + +#define _syscall0(type,name) \ +type name(void) \ +{ \ + long retval; \ + __asm__ ( \ + "li 0, %0 \n\t" \ + "sc \n\t" \ + "mr 31,3 \n\t" \ + "bns 10f \n\t" \ + "mr 0,3 \n\t" \ + "lis 3,errno@ha \n\t" \ + "stw 0,errno@l(3) \n\t" \ + "li 3,-1 \n\t" \ + "10: \n\t" \ + : \ + : "i" (__NR_##name) \ + : "0", "31", "3", "cc", "memory" \ + ); \ + return(retval);\ +} + +#define _syscall1(type,name,type1,arg1) \ +type name(type1 arg1) \ +{ \ + long retval; \ + __asm__ ( \ + "li 0, %0 \n\t" \ + "sc \n\t" \ + "mr 31,3 \n\t" \ + "bns 10f \n\t" \ + "mr 0,3 \n\t" \ + "lis 3,errno@ha \n\t" \ + "stw 0,errno@l(3) \n\t" \ + "li 3,-1 \n\t" \ + "10: \n\t" \ + : \ + : "i" (__NR_##name) \ + : "0", "31", "3", "cc", "memory" \ + ); \ + return(retval); \ +} + +#define _syscall2(type,name,type1,arg1,type2,arg2) \ +type name(type1 arg1,type2 arg2) \ +{ \ + long retval; \ + __asm__ ( \ + "li 0, %0 \n\t" \ + "sc \n\t" \ + "mr 31,3 \n\t" \ + "bns 10f \n\t" \ + "mr 0,3 \n\t" \ + "lis 3,errno@ha \n\t" \ + "stw 0,errno@l(3) \n\t" \ + "li 3,-1 \n\t" \ + "10: \n\t" \ + : \ + : "i" (__NR_##name) \ + : "0", "31", "3", "cc", "memory" \ + ); \ + return(retval); \ +} + + +#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ +type name(type1 arg1,type2 arg2, type3 arg3) \ +{ \ + long retval; \ + __asm__ ( \ + "li 0, %0 \n\t" \ + "sc \n\t" \ + "mr 31,3 \n\t" \ + "bns 10f \n\t" \ + "mr 0,3 \n\t" \ + "lis 3,errno@ha \n\t" \ + "stw 0,errno@l(3) \n\t" \ + "li 3,-1 \n\t" \ + "10: \n\t" \ + : \ + : "i" (__NR_##name) \ + : "0", "31", "3", "cc", "memory" \ + ); \ + return(retval); \ +} + +#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ +type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4) \ +{ \ + long retval; \ + __asm__ ( \ + "li 0, %0 \n\t" \ + "sc \n\t" \ + "mr 31,3 \n\t" \ + "bns 10f \n\t" \ + "mr 0,3 \n\t" \ + "lis 3,errno@ha \n\t" \ + "stw 0,errno@l(3) \n\t" \ + "li 3,-1 \n\t" \ + "10: \n\t" \ + : \ + : "i" (__NR_##name) \ + : "0", "31", "3", "cc", "memory" \ + ); \ + return(retval); \ +} + +#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4, \ + type5,arg5) \ +type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \ +{ \ + long retval; \ + __asm__ ( \ + "li 0, %0 \n\t" \ + "sc \n\t" \ + "mr 31,3 \n\t" \ + "bns 10f \n\t" \ + "mr 0,3 \n\t" \ + "lis 3,errno@ha \n\t" \ + "stw 0,errno@l(3) \n\t" \ + "li 3,-1 \n\t" \ + "10: \n\t" \ + : \ + : "i" (__NR_##name) \ + : "0", "31", "3", "cc", "memory" \ + ); \ + return(retval); \ +} + +#ifdef __KERNEL_SYSCALLS__ +/* + * we need this inline - forking from kernel space will result + * in NO COPY ON WRITE (!!!), until an execve is executed. This + * is no problem, but for the stack. This is handled by not letting + * main() use the stack at all after fork(). Thus, no function + * calls - which means inline code for fork too, as otherwise we + * would use the stack upon exit from 'fork()'. + * + * Actually only pause and fork are needed inline, so that there + * won't be any messing with the stack from main(), but we define + * some others too. + */ + +/* + some of these had problems getting the right arguments (namely sys_clone()) + when they were inline so I made them non-inline until we get problems with gcc + worked out. I need to check with Linus to find out which he wants inline now + since the above comment was written a long time ago. + + Once I understand the macro language better this should go away. + -- Cort + */ + +#define __NR__exit __NR_exit +static /*__inline__*/ _syscall0(int,setup) +static __inline__ _syscall0(int,idle) +static /*__inline__*/ _syscall0(int,fork) +static __inline__ _syscall0(int,pause) +static __inline__ _syscall0(int,sync) +static __inline__ _syscall0(pid_t,setsid) +static __inline__ _syscall3(int,write,int,fd,const char *,buf,off_t,count) +static /*__inline__*/ _syscall1(int,dup,int,fd) +static /*__inline__*/ _syscall3(int,execve,const char *,file,char **,argv,char **,envp) +static __inline__ _syscall3(int,open,const char *,file,int,flag,int,mode) +static /*__inline__*/ _syscall1(int,close,int,fd) +static /*__inline__*/ _syscall1(int,_exit,int,exitcode) +static __inline__ _syscall2(int,clone,unsigned long,flags,char *,esp) +static __inline__ _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) + +static __inline__ pid_t wait(int * wait_stat) +{ + return waitpid(-1,wait_stat,0); +} + +/* + This is the mechanism for creating a new kernel thread. + For the time being it only behaves the same as clone(). + It should be changed very soon to work properly and cleanly. This + gets us going for now, though. + -- Cort + */ +static __inline__ long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) +{ + long retval; + __asm__ ( + "li 0, 120 \n\t" /* __NR_clone */ + "li 3, %5 \n\t" /* load flags as arg to clone */ + /*"mr 1,7 \n\t"*/ /* save kernel stack */ + "sc \n\t" /* syscall */ + /*"cmp 0,1,7 \n\t"*/ /* if kernel stack changes -- child */ + "cmpi 0,3,0 \n\t" + "bne 1f \n\t" /* return if parent */ + /* this is in child */ + "li 3, %3 \n\t" /* child -- load args and call fn */ + "mtlr %4 \n\t" + "blrl \n\t" + "li 0, %2 \n\t" /* exit after child exits */ + "li 3, 0 \n\t" + "sc \n\t" + /* parent */ + "1: \n\t" + :"=3" (retval) + :"i" (__NR_clone), "i" (__NR_exit), + "r" (arg), "r" (fn), "g" (CLONE_VM|flags) + :"cc", "1", "0", "3", "7", "31", "memory" ); + return retval; +} + + +#endif /* __KERNEL_SYSCALLS__ */ + +#endif /* _ASM_PPC_UNISTD_H_ */ diff -ur --new-file old/linux/include/asm-sparc/elf.h new/linux/include/asm-sparc/elf.h --- old/linux/include/asm-sparc/elf.h Thu Apr 25 12:23:18 1996 +++ new/linux/include/asm-sparc/elf.h Sun Aug 4 13:12:40 1996 @@ -15,6 +15,19 @@ typedef unsigned long elf_fpregset_t; +/* + * This is used to ensure we don't load something for the wrong architecture. + */ #define elf_check_arch(x) ((x) == EM_SPARC) + +/* + * These are used to set parameters in the core dumps. + */ #define ELF_ARCH EM_SPARC +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2MSB; + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + #endif diff -ur --new-file old/linux/include/linux/a.out.h new/linux/include/linux/a.out.h --- old/linux/include/linux/a.out.h Mon May 6 11:44:32 1996 +++ new/linux/include/linux/a.out.h Mon Aug 12 10:45:46 1996 @@ -94,15 +94,15 @@ #endif #if !defined (N_DRELOFF) -#define N_DRELOFF(x) (N_TRELOFF(x) + (x).a_trsize) +#define N_DRELOFF(x) (N_TRELOFF(x) + N_TRSIZE(x)) #endif #if !defined (N_SYMOFF) -#define N_SYMOFF(x) (N_DRELOFF(x) + (x).a_drsize) +#define N_SYMOFF(x) (N_DRELOFF(x) + N_DRSIZE(x)) #endif #if !defined (N_STROFF) -#define N_STROFF(x) (N_SYMOFF(x) + (x).a_syms) +#define N_STROFF(x) (N_SYMOFF(x) + N_SYMSIZE(x)) #endif /* Address of text segment in memory after it is loaded. */ diff -ur --new-file old/linux/include/linux/affs_fs.h new/linux/include/linux/affs_fs.h --- old/linux/include/linux/affs_fs.h Mon Jun 3 11:20:48 1996 +++ new/linux/include/linux/affs_fs.h Sun Aug 4 14:14:16 1996 @@ -69,7 +69,8 @@ const char *symname); extern int affs_fixup(struct buffer_head *bh, struct inode *inode); extern int affs_rename(struct inode *old_dir, const char *old_name, int old_len, - struct inode *new_dir, const char *new_name, int new_len); + struct inode *new_dir, const char *new_name, int new_len, + int must_be_dir); /* inode.c */ diff -ur --new-file old/linux/include/linux/affs_fs_sb.h new/linux/include/linux/affs_fs_sb.h --- old/linux/include/linux/affs_fs_sb.h Mon May 20 07:38:41 1996 +++ new/linux/include/linux/affs_fs_sb.h Thu Jul 25 08:08:28 1996 @@ -64,7 +64,6 @@ #define SF_SETUID 0x0010 /* Ignore Amiga uid */ #define SF_SETGID 0x0020 /* Ignore Amiga gid */ #define SF_SETMODE 0x0040 /* Ignore Amiga protection bits */ -#define SF_USE_MP 0x0080 /* Use uid and gid from mount point */ #define SF_MUFS 0x0100 /* Use MUFS uid/gid mapping */ #define SF_OFS 0x0200 /* Old filesystem */ #define SF_PREFIX 0x0400 /* Buffer for prefix is allocated */ diff -ur --new-file old/linux/include/linux/ax25.h new/linux/include/linux/ax25.h --- old/linux/include/linux/ax25.h Mon Apr 1 09:46:30 1996 +++ new/linux/include/linux/ax25.h Wed Aug 7 07:41:57 1996 @@ -1,59 +1,14 @@ +/* + * These are the public elements of the Linux kernel AX.25 code. A similar + * file netrom.h exists for the NET/ROM protocol. + */ + +#ifndef AX25_KERNEL_H +#define AX25_KERNEL_H + #define PF_AX25 AF_AX25 #define AX25_MTU 256 -#define AX25_MAX_DIGIS 6 - -typedef struct -{ - char ax25_call[7]; /* 6 call + SSID (shifted ascii!) */ -} -ax25_address; - -struct sockaddr_ax25 -{ - short sax25_family; - ax25_address sax25_call; - int sax25_ndigis; - /* Digipeater ax25_address sets follow */ -}; - -#define sax25_uid sax25_ndigis - -struct full_sockaddr_ax25 -{ - struct sockaddr_ax25 fsa_ax25; - ax25_address fsa_digipeater[AX25_MAX_DIGIS]; -}; - -struct ax25_routes_struct -{ - ax25_address port_addr; - ax25_address dest_addr; - unsigned char digi_count; - ax25_address digi_addr[AX25_MAX_DIGIS]; -}; - -struct ax25_route_opt_struct -{ - ax25_address port_addr; - ax25_address dest_addr; - int cmd; - int arg; -}; - -struct ax25_ctl_struct -{ - ax25_address port_addr; - ax25_address source_addr; - ax25_address dest_addr; - unsigned int cmd; - unsigned long arg; -}; - -struct ax25_bpqaddr_struct -{ - char dev[16]; - ax25_address addr; -}; +#define AX25_MAX_DIGIS 6 /* This is wrong, should be 8 */ #define AX25_WINDOW 1 #define AX25_T1 2 @@ -79,16 +34,8 @@ #define SIOCAX25OPTRT (SIOCPROTOPRIVATE+7) #define SIOCAX25CTLCON (SIOCPROTOPRIVATE+8) -#define AX25_SET_RT_PERMANENT 1 #define AX25_SET_RT_IPMODE 2 -#define AX25_RT_DYNAMIC 0 -#define AX25_RT_PERMANENT 1 - -#define AX25_RT_IPMODE_DEFAULT ' ' -#define AX25_RT_IPMODE_DATAGRAM 'D' -#define AX25_RT_IPMODE_VC 'V' - #define AX25_NOUID_DEFAULT 0 #define AX25_NOUID_BLOCK 1 @@ -113,8 +60,54 @@ #define AX25_VALUES_IPMAXQUEUE 15 /* Maximum number of buffers enqueued */ #define AX25_MAX_VALUES 20 -struct ax25_parms_struct -{ +typedef struct { + char ax25_call[7]; /* 6 call + SSID (shifted ascii!) */ +} ax25_address; + +struct sockaddr_ax25 { + short sax25_family; + ax25_address sax25_call; + int sax25_ndigis; + /* Digipeater ax25_address sets follow */ +}; + +#define sax25_uid sax25_ndigis + +struct full_sockaddr_ax25 { + struct sockaddr_ax25 fsa_ax25; + ax25_address fsa_digipeater[AX25_MAX_DIGIS]; +}; + +struct ax25_routes_struct { + ax25_address port_addr; + ax25_address dest_addr; + unsigned char digi_count; + ax25_address digi_addr[AX25_MAX_DIGIS]; +}; + +struct ax25_route_opt_struct { + ax25_address port_addr; + ax25_address dest_addr; + int cmd; + int arg; +}; + +struct ax25_ctl_struct { + ax25_address port_addr; + ax25_address source_addr; + ax25_address dest_addr; + unsigned int cmd; + unsigned long arg; +}; + +struct ax25_bpqaddr_struct { + char dev[16]; + ax25_address addr; +}; + +struct ax25_parms_struct { ax25_address port_addr; unsigned short values[AX25_MAX_VALUES]; }; + +#endif diff -ur --new-file old/linux/include/linux/baycom.h new/linux/include/linux/baycom.h --- old/linux/include/linux/baycom.h Thu Jun 6 13:22:57 1996 +++ new/linux/include/linux/baycom.h Mon Jul 8 09:21:46 1996 @@ -8,6 +8,7 @@ #define _BAYCOM_H #include +#undef BAYCOM_DEBUG /* -------------------------------------------------------------------- */ diff -ur --new-file old/linux/include/linux/blk.h new/linux/include/linux/blk.h --- old/linux/include/linux/blk.h Sun Jun 9 11:23:32 1996 +++ new/linux/include/linux/blk.h Tue Aug 20 17:09:33 1996 @@ -310,7 +310,8 @@ #endif /* MAJOR_NR == whatever */ -#if ((MAJOR_NR != SCSI_TAPE_MAJOR) && !defined(IDE_DRIVER)) +#if (MAJOR_NR != SCSI_TAPE_MAJOR) +#if !defined(IDE_DRIVER) #ifndef CURRENT #define CURRENT (blk_dev[MAJOR_NR].current_request) @@ -362,12 +363,12 @@ panic(DEVICE_NAME ": block not locked"); \ } -#endif /* (MAJOR_NR != SCSI_TAPE_MAJOR) && !defined(IDE_DRIVER) */ +#endif /* !defined(IDE_DRIVER) */ /* end_request() - SCSI devices have their own version */ /* - IDE drivers have their own copy too */ -#if ! SCSI_MAJOR(MAJOR_NR) +#if ! SCSI_BLK_MAJOR(MAJOR_NR) #if defined(IDE_DRIVER) && !defined(_IDE_C) /* shared copy for IDE modules */ void ide_end_request(byte uptodate, ide_hwgroup_t *hwgroup); @@ -423,7 +424,8 @@ wake_up(&wait_for_request); } #endif /* defined(IDE_DRIVER) && !defined(_IDE_C) */ -#endif /* ! SCSI_MAJOR(MAJOR_NR) */ +#endif /* ! SCSI_BLK_MAJOR(MAJOR_NR) */ +#endif /* (MAJOR_NR != SCSI_TAPE_MAJOR) */ #endif /* defined(MAJOR_NR) || defined(IDE_DRIVER) */ diff -ur --new-file old/linux/include/linux/dirent.h new/linux/include/linux/dirent.h --- old/linux/include/linux/dirent.h Tue Aug 15 17:31:52 1995 +++ new/linux/include/linux/dirent.h Wed Jul 10 06:38:08 1996 @@ -1,13 +1,11 @@ #ifndef _LINUX_DIRENT_H #define _LINUX_DIRENT_H -#include - struct dirent { long d_ino; - off_t d_off; + __kernel_off_t d_off; unsigned short d_reclen; - char d_name[NAME_MAX+1]; + char d_name[256]; /* We must not include limits.h! */ }; #endif diff -ur --new-file old/linux/include/linux/elf.h new/linux/include/linux/elf.h --- old/linux/include/linux/elf.h Mon May 27 11:00:59 1996 +++ new/linux/include/linux/elf.h Wed Aug 7 09:08:46 1996 @@ -1,6 +1,8 @@ #ifndef _LINUX_ELF_H #define _LINUX_ELF_H +#include + typedef unsigned long Elf32_Addr; typedef unsigned short Elf32_Half; typedef unsigned long Elf32_Off; @@ -36,7 +38,25 @@ #define EM_88K 5 #define EM_486 6 /* Perhaps disused */ #define EM_860 7 -#define EM_PPC 20 + +#define EM_MIPS 8 /* MIPS R3000 (officially, big-endian only) */ + +#define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */ + +#define EM_SPARC64 11 /* SPARC v9 (not official) 64-bit */ + +#define EM_PARISC 15 /* HPPA */ + +#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ + +#define EM_PPC 20 /* PowerPC */ + +/* + * This is an interim value that we will use until the committee comes + * up with a final number. + */ +#define EM_ALPHA 0x9026 + /* This is the info that is needed to parse the dynamic section of the file */ #define DT_NULL 0 @@ -107,7 +127,13 @@ } d_un; } Elf32_Dyn; -extern Elf32_Dyn _DYNAMIC []; +typedef struct { + unsigned long long d_tag; /* entry tag value */ + union { + unsigned long long d_val; + unsigned long long d_ptr; + } d_un; +} Elf64_Dyn; /* The following are used with relocations */ #define ELF32_R_SYM(x) ((x) >> 8) @@ -131,12 +157,23 @@ Elf32_Word r_info; } Elf32_Rel; +typedef struct elf64_rel { + unsigned long long r_offset; /* Location at which to apply the action */ + unsigned long long r_info; /* index and type of relocation */ +} Elf64_Rel; + typedef struct elf32_rela{ Elf32_Addr r_offset; Elf32_Word r_info; Elf32_Sword r_addend; } Elf32_Rela; +typedef struct elf64_rela { + unsigned long long r_offset; /* Location at which to apply the action */ + unsigned long long r_info; /* index and type of relocation */ + unsigned long long r_addend; /* Constant addend used to compute value */ +} Elf64_Rela; + typedef struct elf32_sym{ Elf32_Word st_name; Elf32_Addr st_value; @@ -146,10 +183,19 @@ Elf32_Half st_shndx; } Elf32_Sym; +typedef struct elf64_sym { + unsigned int st_name; /* Symbol name, index in string tbl */ + unsigned char st_info; /* Type and binding attributes */ + unsigned char st_other; /* No defined meaning, 0 */ + unsigned short st_shndx; /* Associated section index */ + unsigned long long st_value; /* Value of the symbol */ + unsigned long long st_size; /* Associated symbol size */ +} Elf64_Sym; + #define EI_NIDENT 16 -typedef struct elfhdr{ +typedef struct elf32_hdr{ unsigned char e_ident[EI_NIDENT]; Elf32_Half e_type; Elf32_Half e_machine; @@ -166,13 +212,30 @@ Elf32_Half e_shstrndx; } Elf32_Ehdr; +typedef struct elf64_hdr { + unsigned char e_ident[16]; /* ELF "magic number" */ + short int e_type; + short unsigned int e_machine; + int e_version; + unsigned long long e_entry; /* Entry point virtual address */ + unsigned long long e_phoff; /* Program header table file offset */ + unsigned long long e_shoff; /* Section header table file offset */ + int e_flags; + short int e_ehsize; + short int e_phentsize; + short int e_phnum; + short int e_shentsize; + short int e_shnum; + short int e_shstrndx; +} Elf64_Ehdr; + /* These constants define the permissions on sections in the program header, p_flags. */ #define PF_R 0x4 #define PF_W 0x2 #define PF_X 0x1 -typedef struct elf_phdr{ +typedef struct elf32_phdr{ Elf32_Word p_type; Elf32_Off p_offset; Elf32_Addr p_vaddr; @@ -183,6 +246,17 @@ Elf32_Word p_align; } Elf32_Phdr; +typedef struct elf64_phdr { + int p_type; + int p_flags; + unsigned long long p_offset; /* Segment file offset */ + unsigned long long p_vaddr; /* Segment virtual address */ + unsigned long long p_paddr; /* Segment physical address */ + unsigned long long p_filesz; /* Segment size in file */ + unsigned long long p_memsz; /* Segment size in memory */ + unsigned long long p_align; /* Segment alignment, file & memory */ +} Elf64_Phdr; + /* sh_type */ #define SHT_NULL 0 #define SHT_PROGBITS 1 @@ -230,6 +304,19 @@ Elf32_Word sh_entsize; } Elf32_Shdr; +typedef struct elf64_shdr { + unsigned int sh_name; /* Section name, index in string tbl */ + unsigned int sh_type; /* Type of section */ + unsigned long long sh_flags; /* Miscellaneous section attributes */ + unsigned long long sh_addr; /* Section virtual addr at execution */ + unsigned long long sh_offset; /* Section file offset */ + unsigned long long sh_size; /* Size of section in bytes */ + unsigned int sh_link; /* Index of another section */ + unsigned int sh_info; /* Additional section information */ + unsigned long long sh_addralign; /* Section alignment */ + unsigned long long sh_entsize; /* Entry size if section holds table */ +} Elf64_Shdr; + #define EI_MAG0 0 /* e_ident[] indexes */ #define EI_MAG1 1 #define EI_MAG2 2 @@ -266,12 +353,41 @@ #define NT_TASKSTRUCT 4 /* Note header in a PT_NOTE section */ -typedef struct elf_note { +typedef struct elf32_note { Elf32_Word n_namesz; /* Name size */ Elf32_Word n_descsz; /* Content size */ Elf32_Word n_type; /* Content type */ } Elf32_Nhdr; +/* Note header in a PT_NOTE section */ +/* + * For now we use the 32 bit version of the structure until we figure + * out whether we need anything better. Note - on the Alpha, "unsigned int" + * is only 32 bits. + */ +typedef struct elf64_note { + unsigned int n_namesz; /* Name size */ + unsigned int n_descsz; /* Content size */ + unsigned int n_type; /* Content type */ +} Elf64_Nhdr; + #define ELF_START_MMAP 0x80000000 + +#if ELF_CLASS == ELFCLASS32 + +extern Elf32_Dyn _DYNAMIC []; +#define elfhdr elf32_hdr +#define elf_phdr elf32_phdr +#define elf_note elf32_note + +#else + +extern Elf64_Dyn _DYNAMIC []; +#define elfhdr elf64_hdr +#define elf_phdr elf64_phdr +#define elf_note elf64_note + +#endif + #endif /* _LINUX_ELF_H */ diff -ur --new-file old/linux/include/linux/elfcore.h new/linux/include/linux/elfcore.h --- old/linux/include/linux/elfcore.h Mon Jun 3 11:20:51 1996 +++ new/linux/include/linux/elfcore.h Mon Aug 5 08:03:18 1996 @@ -40,9 +40,9 @@ short pr_what; /* XXX More detailed reason */ #endif struct elf_siginfo pr_info; /* Info associated with signal */ - short pr_cursig; /* Current signal */ - sigset_t pr_sigpend; /* Set of pending signals */ - sigset_t pr_sighold; /* Set of held signals */ + short pr_cursig; /* Current signal */ + sigset_t pr_sigpend; /* Set of pending signals */ + sigset_t pr_sighold; /* Set of held signals */ #if 0 struct sigaltstack pr_altstack; /* Alternate stack info */ struct sigaction pr_action; /* Signal action for current sig */ diff -ur --new-file old/linux/include/linux/ext2_fs.h new/linux/include/linux/ext2_fs.h --- old/linux/include/linux/ext2_fs.h Fri Jun 7 14:45:21 1996 +++ new/linux/include/linux/ext2_fs.h Sun Aug 4 13:38:04 1996 @@ -495,7 +495,7 @@ extern int ext2_link (struct inode *, struct inode *, const char *, int); extern int ext2_mknod (struct inode *, const char *, int, int, int); extern int ext2_rename (struct inode *, const char *, int, - struct inode *, const char *, int); + struct inode *, const char *, int, int); /* super.c */ extern void ext2_error (struct super_block *, const char *, const char *, ...) diff -ur --new-file old/linux/include/linux/ext_fs.h new/linux/include/linux/ext_fs.h --- old/linux/include/linux/ext_fs.h Mon Jan 15 06:59:13 1996 +++ new/linux/include/linux/ext_fs.h Wed Jul 3 10:53:06 1996 @@ -74,7 +74,7 @@ extern int ext_link(struct inode * oldinode, struct inode * dir, const char * name, int len); extern int ext_mknod(struct inode * dir, const char * name, int len, int mode, int rdev); extern int ext_rename(struct inode * old_dir, const char * old_name, int old_len, - struct inode * new_dir, const char * new_name, int new_len); + struct inode * new_dir, const char * new_name, int new_len, int must_be_dir); extern struct inode * ext_new_inode(const struct inode * dir); extern void ext_free_inode(struct inode * inode); extern unsigned long ext_count_free_inodes(struct super_block *sb); diff -ur --new-file old/linux/include/linux/file.h new/linux/include/linux/file.h --- old/linux/include/linux/file.h Thu Jan 1 01:00:00 1970 +++ new/linux/include/linux/file.h Tue Aug 20 11:14:31 1996 @@ -0,0 +1,25 @@ +#ifndef __LINUX_FILE_H +#define __LINUX_FILE_H + +extern inline struct file * fget(unsigned long fd) +{ + struct file * file = NULL; + if (fd < NR_OPEN) { + file = current->files->fd[fd]; + if (file) + file->f_count++; + } + return file; +} + +extern void __fput(struct file *, struct inode *); + +extern inline void fput(struct file *file, struct inode *inode) +{ + int count = file->f_count-1; + if (!count) + __fput(file, inode); + file->f_count = count; +} + +#endif diff -ur --new-file old/linux/include/linux/fs.h new/linux/include/linux/fs.h --- old/linux/include/linux/fs.h Sun Jun 9 11:23:32 1996 +++ new/linux/include/linux/fs.h Tue Aug 20 17:09:33 1996 @@ -478,7 +478,7 @@ int (*mkdir) (struct inode *,const char *,int,int); int (*rmdir) (struct inode *,const char *,int); int (*mknod) (struct inode *,const char *,int,int,int); - int (*rename) (struct inode *,const char *,int,struct inode *,const char *,int); + int (*rename) (struct inode *,const char *,int,struct inode *,const char *,int, int); int (*readlink) (struct inode *,char *,int); int (*follow_link) (struct inode *,struct inode *,int,int,struct inode **); int (*readpage) (struct inode *, struct page *); @@ -623,6 +623,8 @@ extern void insert_inode_hash(struct inode *); extern void clear_inode(struct inode *); extern struct inode * get_pipe_inode(void); +extern int get_unused_fd(void); +extern void put_unused_fd(int); extern struct file * get_empty_filp(void); extern int close_fp(struct file *filp); extern struct buffer_head * get_hash_table(kdev_t dev, int block, int size); diff -ur --new-file old/linux/include/linux/if_arp.h new/linux/include/linux/if_arp.h --- old/linux/include/linux/if_arp.h Fri May 31 12:46:27 1996 +++ new/linux/include/linux/if_arp.h Tue Aug 20 17:11:38 1996 @@ -22,6 +22,7 @@ #ifndef _LINUX_IF_ARP_H #define _LINUX_IF_ARP_H +#include /* ARP protocol HARDWARE identifiers. */ #define ARPHRD_NETROM 0 /* from KA9Q: NET/ROM pseudo */ diff -ur --new-file old/linux/include/linux/if_strip.h new/linux/include/linux/if_strip.h --- old/linux/include/linux/if_strip.h Tue Apr 2 11:12:35 1996 +++ new/linux/include/linux/if_strip.h Wed Aug 14 09:21:03 1996 @@ -18,10 +18,8 @@ #ifndef __LINUX_STRIP_H #define __LINUX_STRIP_H -typedef union { - __u32 l; - __u16 s[2]; - __u8 c[4]; +typedef struct { + __u8 c[6]; } MetricomAddress; #endif diff -ur --new-file old/linux/include/linux/igmp.h new/linux/include/linux/igmp.h --- old/linux/include/linux/igmp.h Thu Nov 30 10:15:53 1995 +++ new/linux/include/linux/igmp.h Sat Aug 17 19:28:10 1996 @@ -1,5 +1,5 @@ /* - * Linux NET3: Internet Gateway Management Protocol [IGMP] + * Linux NET3: Internet Group Management Protocol [IGMP] * * Authors: * Alan Cox diff -ur --new-file old/linux/include/linux/in.h new/linux/include/linux/in.h --- old/linux/include/linux/in.h Mon Jun 3 11:15:26 1996 +++ new/linux/include/linux/in.h Sat Aug 17 19:28:10 1996 @@ -24,7 +24,7 @@ enum { IPPROTO_IP = 0, /* Dummy protocol for TCP */ IPPROTO_ICMP = 1, /* Internet Control Message Protocol */ - IPPROTO_IGMP = 2, /* Internet Gateway Management Protocol */ + IPPROTO_IGMP = 2, /* Internet Group Management Protocol */ IPPROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94) */ IPPROTO_TCP = 6, /* Transmission Control Protocol */ IPPROTO_EGP = 8, /* Exterior Gateway Protocol */ @@ -101,7 +101,7 @@ #define INADDR_BROADCAST ((unsigned long int) 0xffffffff) /* Address indicating an error return. */ -#define INADDR_NONE 0xffffffff +#define INADDR_NONE ((unsigned long int) 0xffffffff) /* Network number for local host loopback. */ #define IN_LOOPBACKNET 127 diff -ur --new-file old/linux/include/linux/isdn.h new/linux/include/linux/isdn.h --- old/linux/include/linux/isdn.h Fri Jun 7 15:02:43 1996 +++ new/linux/include/linux/isdn.h Sat Jun 29 19:36:23 1996 @@ -1,4 +1,4 @@ -/* $Id: isdn.h,v 1.14 1996/06/06 21:24:23 fritz Exp $ +/* $Id: isdn.h,v 1.15 1996/06/15 14:56:57 fritz Exp $ * * Main header for the Linux ISDN subsystem (linklevel). * @@ -21,6 +21,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn.h,v $ + * Revision 1.15 1996/06/15 14:56:57 fritz + * Added version signatures for data structures used + * by userlevel programs. + * * Revision 1.14 1996/06/06 21:24:23 fritz * Started adding support for suspend/resume. * @@ -118,6 +122,7 @@ #define IIOCNETASL _IO('I',19) #define IIOCNETDIL _IO('I',20) #define IIOCGETCPS _IO('I',21) +#define IIOCGETDVR _IO('I',22) #define IIOCNETALN _IO('I',32) #define IIOCNETDLN _IO('I',33) @@ -164,6 +169,9 @@ char phone[20]; int outgoing; } isdn_net_ioctl_phone; + +#define NET_DV 0x01 /* Data version for net_cfg */ +#define TTY_DV 0x01 /* Data version for iprofd etc. */ typedef struct { char name[10]; /* Name of interface */ diff -ur --new-file old/linux/include/linux/loop.h new/linux/include/linux/loop.h --- old/linux/include/linux/loop.h Sun Mar 24 19:07:01 1996 +++ new/linux/include/linux/loop.h Mon Jul 1 19:06:05 1996 @@ -32,6 +32,10 @@ des_key_schedule lo_des_key; unsigned long lo_des_init[2]; #endif +#ifdef IDEA_AVAILABLE + idea_key lo_idea_en_key; + idea_key lo_idea_de_key; +#endif }; typedef int (* transfer_proc_t)(struct loop_device *, int cmd, diff -ur --new-file old/linux/include/linux/major.h new/linux/include/linux/major.h --- old/linux/include/linux/major.h Fri Apr 26 09:30:52 1996 +++ new/linux/include/linux/major.h Thu Aug 15 08:54:46 1996 @@ -42,9 +42,9 @@ #define MITSUMI_X_CDROM_MAJOR 20 #define SCSI_GENERIC_MAJOR 21 #define Z8530_MAJOR 34 -#define DIGI_MAJOR 22 +#define DIGI_MAJOR 23 #define IDE1_MAJOR 22 -#define DIGICU_MAJOR 23 +#define DIGICU_MAJOR 22 #define MITSUMI_CDROM_MAJOR 23 #define CDU535_CDROM_MAJOR 24 #define STL_SERIALMAJOR 24 @@ -73,14 +73,12 @@ * Tests for SCSI devices. */ -#define SCSI_MAJOR(M) \ +#define SCSI_BLK_MAJOR(M) \ ((M) == SCSI_DISK_MAJOR \ - || (M) == SCSI_TAPE_MAJOR \ - || (M) == SCSI_CDROM_MAJOR \ - || (M) == SCSI_GENERIC_MAJOR) + || (M) == SCSI_CDROM_MAJOR) -static inline int scsi_major(int m) { - return SCSI_MAJOR(m); +static inline int scsi_blk_major(int m) { + return SCSI_BLK_MAJOR(m); } #endif diff -ur --new-file old/linux/include/linux/minix_fs.h new/linux/include/linux/minix_fs.h --- old/linux/include/linux/minix_fs.h Mon Jan 15 06:59:14 1996 +++ new/linux/include/linux/minix_fs.h Wed Jul 3 10:53:06 1996 @@ -100,7 +100,7 @@ extern int minix_link(struct inode * oldinode, struct inode * dir, const char * name, int len); extern int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev); extern int minix_rename(struct inode * old_dir, const char * old_name, int old_len, - struct inode * new_dir, const char * new_name, int new_len); + struct inode * new_dir, const char * new_name, int new_len, int must_be_dir); extern struct inode * minix_new_inode(const struct inode * dir); extern void minix_free_inode(struct inode * inode); extern unsigned long minix_count_free_inodes(struct super_block *sb); diff -ur --new-file old/linux/include/linux/mm.h new/linux/include/linux/mm.h --- old/linux/include/linux/mm.h Sun Jun 9 11:23:32 1996 +++ new/linux/include/linux/mm.h Tue Aug 20 17:09:33 1996 @@ -112,21 +112,21 @@ * here (16 bytes or greater). This ordering should be particularly * beneficial on 32-bit processors. * - * The first line is data used in linear searches (eg. clock algorithm - * scans). The second line is data used in page searches through the - * page-cache. -- sct + * The first line is data used in page cache lookup, the second line + * is used for linear searches (eg. clock algorithm scans). */ typedef struct page { + /* these must be first (free area handling) */ + struct page *next; + struct page *prev; + struct inode *inode; + unsigned long offset; + struct page *next_hash; atomic_t count; + unsigned flags; /* atomic flags, some possibly updated asynchronously */ unsigned dirty:16, age:8; - unsigned flags; /* atomic flags, some possibly updated asynchronously */ struct wait_queue *wait; - struct page *next; - struct page *next_hash; - unsigned long offset; - struct inode *inode; - struct page *prev; struct page *prev_hash; struct buffer_head * buffers; unsigned long swap_unlock_entry; @@ -248,6 +248,7 @@ #define free_page(addr) free_pages((addr),0) extern void free_pages(unsigned long addr, unsigned long order); +extern void __free_page(struct page *); extern void show_free_areas(void); extern unsigned long put_dirty_page(struct task_struct * tsk,unsigned long page, @@ -318,7 +319,8 @@ unsigned long grow; address &= PAGE_MASK; - if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur) + if (vma->vm_end - address + > (unsigned long) current->rlim[RLIMIT_STACK].rlim_cur) return -ENOMEM; grow = vma->vm_start - address; vma->vm_start = address; diff -ur --new-file old/linux/include/linux/msdos_fs.h new/linux/include/linux/msdos_fs.h --- old/linux/include/linux/msdos_fs.h Sun Jun 9 11:26:55 1996 +++ new/linux/include/linux/msdos_fs.h Tue Aug 20 17:13:00 1996 @@ -251,7 +251,8 @@ extern int msdos_unlink(struct inode *dir,const char *name,int len); extern int msdos_unlink_umsdos(struct inode *dir,const char *name,int len); extern int msdos_rename(struct inode *old_dir,const char *old_name,int old_len, - struct inode *new_dir,const char *new_name,int new_len); + struct inode *new_dir,const char *new_name,int new_len, + int must_be_dir); /* fatfs_syms.c */ extern int init_fat_fs(void); @@ -263,7 +264,8 @@ extern int vfat_mkdir(struct inode *dir,const char *name,int len,int mode); extern int vfat_rmdir(struct inode *dir,const char *name,int len); extern int vfat_rename(struct inode *old_dir,const char *old_name,int old_len, - struct inode *new_dir,const char *new_name,int new_len); + struct inode *new_dir,const char *new_name,int new_len, + int must_be_dir); extern void vfat_put_super(struct super_block *sb); extern struct super_block *vfat_read_super(struct super_block *sb,void *data, int silent); diff -ur --new-file old/linux/include/linux/mtio.h new/linux/include/linux/mtio.h --- old/linux/include/linux/mtio.h Fri May 3 09:12:17 1996 +++ new/linux/include/linux/mtio.h Sun Aug 4 12:39:07 1996 @@ -74,8 +74,8 @@ long mt_gstat; /* generic (device independent) status */ long mt_erreg; /* error register */ /* The next two fields are not always used */ - daddr_t mt_fileno; /* number of current file on tape */ - daddr_t mt_blkno; /* current block number */ + __kernel_daddr_t mt_fileno; /* number of current file on tape */ + __kernel_daddr_t mt_blkno; /* current block number */ }; diff -ur --new-file old/linux/include/linux/ncp.h new/linux/include/linux/ncp.h --- old/linux/include/linux/ncp.h Mon Jun 3 11:20:48 1996 +++ new/linux/include/linux/ncp.h Sun Aug 4 14:14:16 1996 @@ -116,6 +116,12 @@ __u16 update_time; }; +/* Defines for Name Spaces */ +#define NW_NS_DOS 0 +#define NW_NS_MAC 1 +#define NW_NS_NFS 2 +#define NW_NS_FTAM 3 +#define NW_NS_OS2 4 /* Defines for ReturnInformationMask */ #define RIM_NAME (0x0001L) diff -ur --new-file old/linux/include/linux/ncp_fs_sb.h new/linux/include/linux/ncp_fs_sb.h --- old/linux/include/linux/ncp_fs_sb.h Mon Jun 3 11:20:48 1996 +++ new/linux/include/linux/ncp_fs_sb.h Sun Aug 4 14:14:16 1996 @@ -21,6 +21,8 @@ interest for us later, so we store it completely. */ + __u8 name_space[NCP_NUMBER_OF_VOLUMES]; + struct file *ncp_filp; /* File pointer to ncp socket */ struct file *wdog_filp; /* File pointer to wdog socket */ struct file *msg_filp; /* File pointer to message socket */ diff -ur --new-file old/linux/include/linux/netdevice.h new/linux/include/linux/netdevice.h --- old/linux/include/linux/netdevice.h Thu Aug 29 16:32:45 1996 +++ new/linux/include/linux/netdevice.h Thu Aug 29 16:33:31 1996 @@ -27,7 +27,6 @@ #include #include #include -#include /* for future expansion when we will have different priorities. */ #define DEV_NUMBUFFS 3 @@ -52,6 +51,10 @@ #define IS_INVBCAST 4 /* Wrong netmask bcast not for us (unused)*/ #define IS_MULTICAST 5 /* Multicast IP address */ +#ifdef __KERNEL__ + +#include + /* * We tag multicasts with these structures. */ @@ -203,8 +206,6 @@ struct packet_type *next; }; - -#ifdef __KERNEL__ #include #include diff -ur --new-file old/linux/include/linux/netrom.h new/linux/include/linux/netrom.h --- old/linux/include/linux/netrom.h Thu Apr 18 13:35:33 1996 +++ new/linux/include/linux/netrom.h Wed Aug 7 07:41:57 1996 @@ -1,3 +1,12 @@ +/* + * These are the public elements of the Linux kernel NET/ROM implementation. + * For kernel AX.25 see the file ax25.h. This file requires ax25.h for the + * definition of the ax25_address structure. + */ + +#ifndef NETROM_KERNEL_H +#define NETROM_KERNEL_H + #define PF_NETROM AF_NETROM #define NETROM_MTU 236 @@ -45,3 +54,5 @@ unsigned int cmd; unsigned long arg; }; + +#endif diff -ur --new-file old/linux/include/linux/nfs_fs.h new/linux/include/linux/nfs_fs.h --- old/linux/include/linux/nfs_fs.h Mon Jun 3 11:15:26 1996 +++ new/linux/include/linux/nfs_fs.h Sun Aug 18 10:19:53 1996 @@ -46,6 +46,10 @@ #define NFS_RENAMED_DIR(inode) ((inode)->u.nfs_i.silly_rename_dir) #define NFS_READTIME(inode) ((inode)->u.nfs_i.read_cache_jiffies) #define NFS_OLDMTIME(inode) ((inode)->u.nfs_i.read_cache_mtime) +#define NFS_ATTRTIMEO(inode) ((inode)->u.nfs_i.attrtimeo) +#define NFS_MINATTRTIMEO(inode) (S_ISREG((inode)->i_mode)? \ + NFS_SERVER(inode)->acregmin : \ + NFS_SERVER(inode)->acdirmin) #define NFS_CACHEINV(inode) \ do { \ NFS_READTIME(inode) = jiffies - 1000000; \ @@ -79,7 +83,8 @@ const char *name); extern int nfs_proc_rename(struct nfs_server *server, struct nfs_fh *old_dir, const char *old_name, - struct nfs_fh *new_dir, const char *new_name); + struct nfs_fh *new_dir, const char *new_name, + int must_be_dir); extern int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fh *dir, const char *name); extern int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir, @@ -96,7 +101,7 @@ extern int nfs_proc_read_request(struct rpc_ioreq *, struct nfs_server *, struct nfs_fh *, unsigned long offset, unsigned long count, __u32 *buf); -extern int nfs_proc_read_reply(struct rpc_ioreq *); +extern int nfs_proc_read_reply(struct rpc_ioreq *, struct nfs_fattr *); extern int *rpc_header(int *p, int procedure, int program, int version, int uid, int gid, int *groups); extern int *rpc_verify(int *p); diff -ur --new-file old/linux/include/linux/nfs_fs_i.h new/linux/include/linux/nfs_fs_i.h --- old/linux/include/linux/nfs_fs_i.h Thu Apr 11 08:20:34 1996 +++ new/linux/include/linux/nfs_fs_i.h Sat Jul 20 07:56:51 1996 @@ -28,6 +28,10 @@ * NFS FH, but that requires a kmalloc. */ struct inode *silly_rename_dir; + /* + * attrtimeo defines for how long the cached attributes are valid + */ + unsigned long attrtimeo; }; #endif diff -ur --new-file old/linux/include/linux/nfsiod.h new/linux/include/linux/nfsiod.h --- old/linux/include/linux/nfsiod.h Thu Jun 6 20:27:06 1996 +++ new/linux/include/linux/nfsiod.h Sun Aug 18 10:24:04 1996 @@ -9,6 +9,7 @@ #define _LINUX_NFSIOD_H #include +#include #ifdef __KERNEL__ @@ -17,7 +18,7 @@ * Note that the callback procedure must NOT sleep. */ struct nfsiod_req; -typedef void (*nfsiod_done_fn_t)(int result, struct nfsiod_req *); +typedef int (*nfsiod_callback_t)(int result, struct nfsiod_req *); /* * This is the nfsiod request struct. @@ -25,16 +26,25 @@ struct nfsiod_req { struct nfsiod_req * rq_next; struct nfsiod_req * rq_prev; - struct nfs_server * rq_server; struct wait_queue * rq_wait; struct rpc_ioreq rq_rpcreq; - nfsiod_done_fn_t rq_callback; - void * rq_cdata; + nfsiod_callback_t rq_callback; + struct nfs_server * rq_server; + struct inode * rq_inode; + struct page * rq_page; + + /* user creds */ + uid_t rq_fsuid; + gid_t rq_fsgid; + int rq_groups[NGROUPS]; + + /* retry handling */ + int rq_retries; }; -struct nfsiod_req * nfsiod_reserve(struct nfs_server *, nfsiod_done_fn_t); +struct nfsiod_req * nfsiod_reserve(struct nfs_server *); void nfsiod_release(struct nfsiod_req *); -int nfsiod_enqueue(struct nfsiod_req *); +void nfsiod_enqueue(struct nfsiod_req *); int nfsiod(void); diff -ur --new-file old/linux/include/linux/pagemap.h new/linux/include/linux/pagemap.h --- old/linux/include/linux/pagemap.h Sun Jun 9 11:23:32 1996 +++ new/linux/include/linux/pagemap.h Tue Aug 20 17:09:33 1996 @@ -17,7 +17,7 @@ return PAGE_OFFSET + PAGE_SIZE * page->map_nr; } -#define PAGE_HASH_BITS 10 +#define PAGE_HASH_BITS 11 #define PAGE_HASH_SIZE (1 << PAGE_HASH_BITS) #define PAGE_AGE_VALUE 16 @@ -48,16 +48,22 @@ { struct page *page; - for (page = page_hash(inode, offset); page ; page = page->next_hash) { + page = page_hash(inode, offset); + goto inside; + for (;;) { + page = page->next_hash; +inside: + if (!page) + goto not_found; if (page->inode != inode) continue; - if (page->offset != offset) - continue; - /* Found the page. */ - atomic_inc(&page->count); - set_bit(PG_referenced, &page->flags); - break; + if (page->offset == offset) + break; } + /* Found the page. */ + atomic_inc(&page->count); + set_bit(PG_referenced, &page->flags); +not_found: return page; } diff -ur --new-file old/linux/include/linux/pci.h new/linux/include/linux/pci.h --- old/linux/include/linux/pci.h Mon May 27 13:01:04 1996 +++ new/linux/include/linux/pci.h Sat Aug 17 20:03:34 1996 @@ -22,7 +22,7 @@ /* PROCEDURE TO REPORT NEW PCI DEVICES - * We are trying to collect informations on new PCI devices, using + * We are trying to collect information on new PCI devices, using * the standard PCI identification procedure. If some warning is * displayed at boot time, please report * - /proc/pci @@ -339,10 +339,10 @@ #define PCI_DEVICE_ID_SGS_2000 0x0008 #define PCI_DEVICE_ID_SGS_1764 0x0009 -#define PCI_VENDOR_ID_BUSLOGIC 0x104B -#define PCI_DEVICE_ID_BUSLOGIC_946C_2 0x0140 -#define PCI_DEVICE_ID_BUSLOGIC_946C 0x1040 -#define PCI_DEVICE_ID_BUSLOGIC_930 0x8130 +#define PCI_VENDOR_ID_BUSLOGIC 0x104B +#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC 0x0140 +#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER 0x1040 +#define PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT 0x8130 #define PCI_VENDOR_ID_OAK 0x104e #define PCI_DEVICE_ID_OAK_OTI107 0x0107 @@ -521,10 +521,14 @@ #define PCI_VENDOR_ID_TEKRAM 0x1de1 #define PCI_DEVICE_ID_TEKRAM_DC290 0xdc29 +#define PCI_VENDOR_ID_3DLABS 0x3D3D +#define PCI_DEVICE_ID_3DLABS_300SX 0x0001 + #define PCI_VENDOR_ID_AVANCE 0x4005 #define PCI_DEVICE_ID_AVANCE_2302 0x2302 #define PCI_VENDOR_ID_S3 0x5333 +#define PCI_DEVICE_ID_S3_ViRGE 0x5631 #define PCI_DEVICE_ID_S3_811 0x8811 #define PCI_DEVICE_ID_S3_868 0x8880 #define PCI_DEVICE_ID_S3_928 0x88b0 @@ -547,6 +551,7 @@ #define PCI_DEVICE_ID_INTEL_82437 0x122d #define PCI_DEVICE_ID_INTEL_82371_0 0x122e #define PCI_DEVICE_ID_INTEL_82371_1 0x1230 +#define PCI_DEVICE_ID_INTEL_82441 0x1237 #define PCI_DEVICE_ID_INTEL_82439 0x1250 #define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000 #define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010 @@ -555,6 +560,7 @@ #define PCI_VENDOR_ID_ADAPTEC 0x9004 #define PCI_DEVICE_ID_ADAPTEC_7850 0x5078 #define PCI_DEVICE_ID_ADAPTEC_7855 0x5578 +#define PCI_DEVICE_ID_ADAPTEC_7860 0x6078 #define PCI_DEVICE_ID_ADAPTEC_7870 0x7078 #define PCI_DEVICE_ID_ADAPTEC_7871 0x7178 #define PCI_DEVICE_ID_ADAPTEC_7872 0x7278 diff -ur --new-file old/linux/include/linux/pcwd.h new/linux/include/linux/pcwd.h --- old/linux/include/linux/pcwd.h Thu Jan 1 01:00:00 1970 +++ new/linux/include/linux/pcwd.h Thu Aug 1 14:43:05 1996 @@ -0,0 +1,12 @@ +/* + * Berkshire PC Watchdog Defines + * For version 0.41 of the driver + */ + +#define PCWD_IOCTL_BASE 'W' + +#define PCWD_GETSTAT _IOR(PCWD_IOCTL_BASE, 1, int) +#define PCWD_PING _IOR(PCWD_IOCTL_BASE, 2, int) + +#define PCWD_PREVRESET 0x01 /* System previously reset by card */ +#define PCWD_TEMPSENSE 0x02 /* Temperature overheat sense */ diff -ur --new-file old/linux/include/linux/personality.h new/linux/include/linux/personality.h --- old/linux/include/linux/personality.h Fri Mar 15 14:22:59 1996 +++ new/linux/include/linux/personality.h Sun Aug 18 08:57:49 1996 @@ -46,6 +46,6 @@ extern struct exec_domain *lookup_exec_domain(unsigned long personality); extern int register_exec_domain(struct exec_domain *it); extern int unregister_exec_domain(struct exec_domain *it); -extern asmlinkage int sys_personality(unsigned long personality); +asmlinkage int sys_personality(unsigned long personality); #endif /* _PERSONALITY_H */ diff -ur --new-file old/linux/include/linux/posix_types.h new/linux/include/linux/posix_types.h --- old/linux/include/linux/posix_types.h Mon Jun 3 11:15:25 1996 +++ new/linux/include/linux/posix_types.h Sun Aug 4 13:37:29 1996 @@ -12,10 +12,10 @@ #endif /* - * This allows for 256 file descriptors: if NR_OPEN is ever grown - * beyond that you'll have to change this too. But 256 fd's seem to be - * enough even for such "real" unices like SunOS, so hopefully this is - * one limit that doesn't have to be changed. + * This allows for 1024 file descriptors: if NR_OPEN is ever grown + * beyond that you'll have to change this too. But 1024 fd's seem to be + * enough even for such "real" unices like OSF/1, so hopefully this is + * one limit that doesn't have to be changed [again]. * * Note that POSIX wants the FD_CLEAR(fd,fdsetp) defines to be in * (and thus ) - but this is a more logical @@ -27,22 +27,22 @@ * use the ones here. */ #undef __NFDBITS -#define __NFDBITS (8 * sizeof(unsigned int)) +#define __NFDBITS (8 * sizeof(unsigned long)) #undef __FD_SETSIZE -#define __FD_SETSIZE 256 +#define __FD_SETSIZE 1024 -#undef __FDSET_INTS -#define __FDSET_INTS (__FD_SETSIZE/__NFDBITS) +#undef __FDSET_LONGS +#define __FDSET_LONGS (__FD_SETSIZE/__NFDBITS) #undef __FDELT #define __FDELT(d) ((d) / __NFDBITS) #undef __FDMASK -#define __FDMASK(d) (1 << ((d) % __NFDBITS)) +#define __FDMASK(d) (1UL << ((d) % __NFDBITS)) typedef struct fd_set { - unsigned int fds_bits [__FDSET_INTS]; + unsigned long fds_bits [__FDSET_LONGS]; } __kernel_fd_set; #include diff -ur --new-file old/linux/include/linux/proc_fs.h new/linux/include/linux/proc_fs.h --- old/linux/include/linux/proc_fs.h Thu Aug 29 16:32:45 1996 +++ new/linux/include/linux/proc_fs.h Thu Aug 29 16:33:32 1996 @@ -103,6 +103,8 @@ PROC_NET_ALIAS_TYPES, PROC_NET_ALIASES, PROC_NET_IP_MASQ_APP, + PROC_NET_STRIP_STATUS, + PROC_NET_STRIP_TRACE, PROC_NET_LAST }; @@ -126,6 +128,7 @@ PROC_SCSI_SEAGATE, PROC_SCSI_T128, PROC_SCSI_NCR53C7xx, + PROC_SCSI_NCR53C8XX, PROC_SCSI_ULTRASTOR, PROC_SCSI_7000FASST, PROC_SCSI_EATA2X, diff -ur --new-file old/linux/include/linux/sbpcd.h new/linux/include/linux/sbpcd.h --- old/linux/include/linux/sbpcd.h Wed Jun 5 08:01:46 1996 +++ new/linux/include/linux/sbpcd.h Mon Aug 12 12:44:47 1996 @@ -106,16 +106,6 @@ /* Set this to 0 once you have configured your interface definitions right. */ #define DISTRIBUTION 1 -#if DISTRIBUTION -#define READ_AUDIO 0 -#define KLOGD_PAUSE 55 -#else -/* max. number of audio frames to read with one */ -/* request (allocates n* 2352 bytes kernel memory!) */ -/* may be freely adjusted, f.e. 75 (= 1 sec.), at */ -/* runtime by use of the CDROMAUDIOBUFSIZ ioctl. */ -#define READ_AUDIO 75 - /* * Time to wait after giving a message. * This gets important if you enable non-standard DBG_xxx flags. @@ -124,13 +114,26 @@ */ #define KLOGD_PAUSE 1 -/* tray control: eject tray if no disk is in (0 or 1) */ +/* tray control: eject tray if no disk is in */ +#if DISTRIBUTION +#define JUKEBOX 0 +#else #define JUKEBOX 1 +#endif DISTRIBUTION -/* tray control: eject tray after last use (0 or 1) */ +/* tray control: eject tray after last use */ +#if DISTRIBUTION +#define EJECT 0 +#else #define EJECT 1 #endif DISTRIBUTION +/* max. number of audio frames to read with one */ +/* request (allocates n* 2352 bytes kernel memory!) */ +/* may be freely adjusted, f.e. 75 (= 1 sec.), at */ +/* runtime by use of the CDROMAUDIOBUFSIZ ioctl. */ +#define READ_AUDIO 0 + /*==========================================================================*/ /*==========================================================================*/ /* @@ -449,6 +452,8 @@ /*==========================================================================*/ #define MAX_TRACKS 99 + +#define ERR_DISKCHANGE 615 /*==========================================================================*/ /* diff -ur --new-file old/linux/include/linux/sched.h new/linux/include/linux/sched.h --- old/linux/include/linux/sched.h Sun Jun 9 11:23:32 1996 +++ new/linux/include/linux/sched.h Tue Aug 20 17:09:33 1996 @@ -108,19 +108,17 @@ asmlinkage void schedule(void); -/* ??? */ +/* Open file table structure */ struct files_struct { - /* ??? */ int count; - /* bit mask to close fds on exec */ fd_set close_on_exec; - /* do we have at most NR_OPEN available fds? I assume fd i maps into - * each open file */ + fd_set open_fds; struct file * fd[NR_OPEN]; }; #define INIT_FILES { \ 1, \ + { { 0, } }, \ { { 0, } }, \ { NULL, } \ } diff -ur --new-file old/linux/include/linux/socket.h new/linux/include/linux/socket.h --- old/linux/include/linux/socket.h Thu Jun 6 20:23:00 1996 +++ new/linux/include/linux/socket.h Mon Jul 8 15:09:16 1996 @@ -102,6 +102,7 @@ #define IPTOS_LOWDELAY 0x10 #define IPTOS_THROUGHPUT 0x08 #define IPTOS_RELIABILITY 0x04 +#define IPTOS_MINCOST 0x02 #define IP_TTL 2 #define IP_HDRINCL 3 #define IP_OPTIONS 4 diff -ur --new-file old/linux/include/linux/soundcard.h new/linux/include/linux/soundcard.h --- old/linux/include/linux/soundcard.h Sat Apr 20 10:18:14 1996 +++ new/linux/include/linux/soundcard.h Sun Jun 30 11:25:28 1996 @@ -58,6 +58,8 @@ #define SNDCARD_MAUI 23 #define SNDCARD_PSEUDO_MSS 24 #define SNDCARD_GUSPNP 25 +#define SNDCARD_UART401 26 +/* Soundcard numbers 27 to N are reserved. Don't add more numbers here */ /*********************************** * IOCTL Commands for /dev/sequencer @@ -140,7 +142,7 @@ * Sample loading mechanism for internal synthesizers (/dev/sequencer) * The following patch_info structure has been designed to support * Gravis UltraSound. It tries to be universal format for uploading - * sample based patches but is probably too limited. + * sample based patches but is propably too limited. */ struct patch_info { @@ -168,6 +170,7 @@ #define WAVE_VIBRATO 0x00010000 /* The vibrato info is valid */ #define WAVE_TREMOLO 0x00020000 /* The tremolo info is valid */ #define WAVE_SCALE 0x00040000 /* The scaling info is valid */ +#define WAVE_FRACTIONS 0x00080000 /* Fraction information is valid */ /* Other bits must be zeroed */ int len; /* Size of the wave data in bytes */ @@ -220,7 +223,8 @@ unsigned int scale_factor; /* from 0 to 2048 or 0 to 2 */ int volume; - int spare[4]; + int fractions; + int spare[3]; char data[1]; /* The waveform data starts here */ }; @@ -259,7 +263,7 @@ * may confuse the patch manager daemon. */ -struct patmgr_info { /* Note! size must be < 4k since kmalloc() is used */ +struct patmgr_info { unsigned int key; /* Don't worry. Reserved for communication between the patch manager and the driver. */ #define PM_K_EVENT 1 /* Event from the /dev/sequencer driver */ @@ -550,7 +554,8 @@ #define SNDCTL_DSP_STEREO _IOWR('P', 3, int) #define SNDCTL_DSP_GETBLKSIZE _IOWR('P', 4, int) #define SNDCTL_DSP_SAMPLESIZE SNDCTL_DSP_SETFMT -#define SOUND_PCM_WRITE_CHANNELS _IOWR('P', 6, int) +#define SNDCTL_DSP_CHANNELS _IOWR('P', 6, int) +#define SOUND_PCM_WRITE_CHANNELS SNDCTL_DSP_CHANNELS #define SOUND_PCM_WRITE_FILTER _IOWR('P', 7, int) #define SNDCTL_DSP_POST _IO ('P', 8) #define SNDCTL_DSP_SUBDIVIDE _IOWR('P', 9, int) @@ -575,7 +580,7 @@ * Buffer status queries. */ typedef struct audio_buf_info { - int fragments; /* # of available fragments (partially used ones not counted) */ + int fragments; /* # of available fragments (partially usend ones not counted) */ int fragstotal; /* Total # of fragments allocated */ int fragsize; /* Size of a fragment in bytes */ @@ -688,7 +693,7 @@ #define SNDCTL_COPR_WCODE _IOW ('C', 5, copr_debug_buf) #define SNDCTL_COPR_RUN _IOWR('C', 6, copr_debug_buf) #define SNDCTL_COPR_HALT _IOWR('C', 7, copr_debug_buf) -#define SNDCTL_COPR_SENDMSG _IOW ('C', 8, copr_msg) +#define SNDCTL_COPR_SENDMSG _IOWR('C', 8, copr_msg) #define SNDCTL_COPR_RCVMSG _IOR ('C', 9, copr_msg) /********************************************* @@ -722,7 +727,7 @@ /* * The AD1848 codec and compatibles have three line level inputs * (line, aux1 and aux2). Since each card manufacturer have assigned - * different meanings to these inputs, it's impractical to assign + * different meanings to these inputs, it's inpractical to assign * specific meanings (line, cd, synth etc.) to them. */ #define SOUND_MIXER_LINE1 14 /* Input source 1 (aux1) */ @@ -737,6 +742,7 @@ /* Note! Number 31 cannot be used since the sign bit is reserved */ +#ifdef NO_LONGER_AVAILABLE /* * The following unsupported macros will be removed from the API in near * future. @@ -744,7 +750,7 @@ #define SOUND_MIXER_ENHANCE 29 /* Enhanced stereo (0, 40, 60 or 80) */ #define SOUND_MIXER_MUTE 28 /* 0 or 1 */ #define SOUND_MIXER_LOUD 30 /* 0 or 1 */ - +#endif #define SOUND_DEVICE_LABELS {"Vol ", "Bass ", "Trebl", "Synth", "Pcm ", "Spkr ", "Line ", \ @@ -784,9 +790,11 @@ #define SOUND_MASK_LINE2 (1 << SOUND_MIXER_LINE2) #define SOUND_MASK_LINE3 (1 << SOUND_MIXER_LINE3) +#ifdef NO_LONGER_AVAILABLE #define SOUND_MASK_MUTE (1 << SOUND_MIXER_MUTE) #define SOUND_MASK_ENHANCE (1 << SOUND_MIXER_ENHANCE) #define SOUND_MASK_LOUD (1 << SOUND_MIXER_LOUD) +#endif #define MIXER_READ(dev) _IOR('M', dev, int) #define SOUND_MIXER_READ_VOLUME MIXER_READ(SOUND_MIXER_VOLUME) @@ -806,9 +814,11 @@ #define SOUND_MIXER_READ_LINE1 MIXER_READ(SOUND_MIXER_LINE1) #define SOUND_MIXER_READ_LINE2 MIXER_READ(SOUND_MIXER_LINE2) #define SOUND_MIXER_READ_LINE3 MIXER_READ(SOUND_MIXER_LINE3) +#ifdef NO_LONGER_AVAILABLE #define SOUND_MIXER_READ_MUTE MIXER_READ(SOUND_MIXER_MUTE) #define SOUND_MIXER_READ_ENHANCE MIXER_READ(SOUND_MIXER_ENHANCE) #define SOUND_MIXER_READ_LOUD MIXER_READ(SOUND_MIXER_LOUD) +#endif #define SOUND_MIXER_READ_RECSRC MIXER_READ(SOUND_MIXER_RECSRC) #define SOUND_MIXER_READ_DEVMASK MIXER_READ(SOUND_MIXER_DEVMASK) @@ -834,12 +844,42 @@ #define SOUND_MIXER_WRITE_LINE1 MIXER_WRITE(SOUND_MIXER_LINE1) #define SOUND_MIXER_WRITE_LINE2 MIXER_WRITE(SOUND_MIXER_LINE2) #define SOUND_MIXER_WRITE_LINE3 MIXER_WRITE(SOUND_MIXER_LINE3) +#ifdef NO_LONGER_AVAILABLE #define SOUND_MIXER_WRITE_MUTE MIXER_WRITE(SOUND_MIXER_MUTE) #define SOUND_MIXER_WRITE_ENHANCE MIXER_WRITE(SOUND_MIXER_ENHANCE) #define SOUND_MIXER_WRITE_LOUD MIXER_WRITE(SOUND_MIXER_LOUD) +#endif #define SOUND_MIXER_WRITE_RECSRC MIXER_WRITE(SOUND_MIXER_RECSRC) +typedef struct mixer_info +{ + char id[16]; + char name[32]; +} mixer_info; + +#define SOUND_MIXER_INFO _IOR ('M', 101, mixer_info) + +/* + * A mechanism for accessing "proprietary" mixer features. This method + * permits passing 128 bytes of arbitrary data between a mixer application + * and the mixer driver. Interpretation of the record is defined by + * the particular mixer driver. + */ +typedef unsigned char mixer_record[128]; + +#define SOUND_MIXER_ACCESS _IOWR('M', 102, mixer_record) + +/* + * The SOUND_MIXER_PRIVATE# commands can be redefined by low level drivers. + * These features can be used when accessing device specific features. + */ +#define SOUND_MIXER_PRIVATE1 _IOWR('M', 111, int) +#define SOUND_MIXER_PRIVATE2 _IOWR('M', 112, int) +#define SOUND_MIXER_PRIVATE3 _IOWR('M', 113, int) +#define SOUND_MIXER_PRIVATE4 _IOWR('M', 114, int) +#define SOUND_MIXER_PRIVATE5 _IOWR('M', 115, int) + /* * Level 2 event types for /dev/sequencer */ @@ -1077,7 +1117,7 @@ #define SEQ_PANNING(dev, voice, pos) SEQ_CONTROL(dev, voice, CTL_PAN, (pos+128) / 2) /* - * Timing and synchronization macros + * Timing and syncronization macros */ #define _TIMER_EVENT(ev, parm) {_SEQ_NEEDBUF(8);\ diff -ur --new-file old/linux/include/linux/string.h new/linux/include/linux/string.h --- old/linux/include/linux/string.h Mon Jun 3 11:15:26 1996 +++ new/linux/include/linux/string.h Sun Aug 4 13:38:04 1996 @@ -13,25 +13,25 @@ extern char * ___strtok; extern char * strcpy(char *,const char *); -extern char * strncpy(char *,const char *,size_t); +extern char * strncpy(char *,const char *, __kernel_size_t); extern char * strcat(char *, const char *); -extern char * strncat(char *, const char *, size_t); +extern char * strncat(char *, const char *, __kernel_size_t); extern char * strchr(const char *,int); extern char * strrchr(const char *,int); extern char * strpbrk(const char *,const char *); extern char * strtok(char *,const char *); extern char * strstr(const char *,const char *); -extern size_t strlen(const char *); -extern size_t strnlen(const char *,size_t); -extern size_t strspn(const char *,const char *); +extern __kernel_size_t strlen(const char *); +extern __kernel_size_t strnlen(const char *,__kernel_size_t); +extern __kernel_size_t strspn(const char *,const char *); extern int strcmp(const char *,const char *); -extern int strncmp(const char *,const char *,size_t); +extern int strncmp(const char *,const char *,__kernel_size_t); -extern void * memset(void *,int,size_t); -extern void * memcpy(void *,const void *,size_t); -extern void * memmove(void *,const void *,size_t); -extern void * memscan(void *,int,size_t); -extern int memcmp(const void *,const void *,size_t); +extern void * memset(void *,int,__kernel_size_t); +extern void * memcpy(void *,const void *,__kernel_size_t); +extern void * memmove(void *,const void *,__kernel_size_t); +extern void * memscan(void *,int,__kernel_size_t); +extern int memcmp(const void *,const void *,__kernel_size_t); /* * Include machine specific inline routines diff -ur --new-file old/linux/include/linux/sysv_fs.h new/linux/include/linux/sysv_fs.h --- old/linux/include/linux/sysv_fs.h Sun Jun 9 11:28:35 1996 +++ new/linux/include/linux/sysv_fs.h Tue Aug 20 17:14:41 1996 @@ -373,7 +373,7 @@ extern int sysv_link(struct inode * oldinode, struct inode * dir, const char * name, int len); extern int sysv_mknod(struct inode * dir, const char * name, int len, int mode, int rdev); extern int sysv_rename(struct inode * old_dir, const char * old_name, int old_len, - struct inode * new_dir, const char * new_name, int new_len); + struct inode * new_dir, const char * new_name, int new_len, int must_be_dir); extern struct inode * sysv_new_inode(const struct inode * dir); extern void sysv_free_inode(struct inode * inode); extern unsigned long sysv_count_free_inodes(struct super_block *sb); diff -ur --new-file old/linux/include/linux/time.h new/linux/include/linux/time.h --- old/linux/include/linux/time.h Tue Feb 13 18:55:59 1996 +++ new/linux/include/linux/time.h Tue Jul 2 18:08:43 1996 @@ -1,10 +1,13 @@ #ifndef _LINUX_TIME_H #define _LINUX_TIME_H +#ifndef _STRUCT_TIMESPEC +#define _STRUCT_TIMESPEC struct timespec { long tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ }; +#endif /* _STRUCT_TIMESPEC */ struct timeval { int tv_sec; /* seconds */ diff -ur --new-file old/linux/include/linux/ucdrom.h new/linux/include/linux/ucdrom.h --- old/linux/include/linux/ucdrom.h Mon May 13 06:36:19 1996 +++ new/linux/include/linux/ucdrom.h Wed Aug 14 09:21:03 1996 @@ -26,7 +26,7 @@ /* specifications */ const int capability; /* capability flags */ int mask; /* mask of capability: disables them */ - const float speed; /* maximum speed for reading data */ + const int speed; /* maximum speed for reading data */ const int minors; /* number of minor devs supported */ const int capacity; /* number of discs in jukebox */ /* device-related storage */ diff -ur --new-file old/linux/include/linux/ultrasound.h new/linux/include/linux/ultrasound.h --- old/linux/include/linux/ultrasound.h Fri Apr 12 08:49:47 1996 +++ new/linux/include/linux/ultrasound.h Sun Jun 30 10:43:41 1996 @@ -6,27 +6,11 @@ * and not portable. */ /* - * Copyright by Hannu Savolainen 1993-1996 + * Copyright (C) by Hannu Savolainen 1993-1996 * - * 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. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * USS/Lite 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. */ @@ -50,7 +34,7 @@ * _GUS_VOICEOFF - Stops voice (no parameters) * _GUS_VOICEFADE - Stops the voice smoothly. * _GUS_VOICEMODE - Alters the voice mode, don't start or stop voice (P1=voice mode) - * _GUS_VOICEBALA - Sets voice balance (P1, 0=left, 7=middle and 15=right, default 7) + * _GUS_VOICEBALA - Sets voice balence (P1, 0=left, 7=middle and 15=right, default 7) * _GUS_VOICEFREQ - Sets voice (sample) playback frequency (P1=Hz) * _GUS_VOICEVOL - Sets voice volume (P1=volume, 0xfff=max, 0xeff=half, 0x000=off) * _GUS_VOICEVOL2 - Sets voice volume (P1=volume, 0xfff=max, 0xeff=half, 0x000=off) diff -ur --new-file old/linux/include/linux/umsdos_fs.p new/linux/include/linux/umsdos_fs.p --- old/linux/include/linux/umsdos_fs.p Tue Aug 1 09:02:47 1995 +++ new/linux/include/linux/umsdos_fs.p Wed Jul 3 15:39:14 1996 @@ -122,7 +122,8 @@ int old_len, struct inode *new_dir, const char *new_name, - int new_len); + int new_len, + int must_be_dir); /* rdir.c 22/03/95 03.31.42 */ int umsdos_rlookup_x (struct inode *dir, const char *name, diff -ur --new-file old/linux/include/linux/xia_fs.h new/linux/include/linux/xia_fs.h --- old/linux/include/linux/xia_fs.h Mon Jan 15 06:59:14 1996 +++ new/linux/include/linux/xia_fs.h Wed Jul 3 10:53:06 1996 @@ -79,7 +79,8 @@ int mode, int rdev); extern int xiafs_rename(struct inode * old_dir, const char * old_name, int old_len, struct inode * new_dir, - const char * new_name, int new_len); + const char * new_name, int new_len, + int must_be_dir); extern struct inode * xiafs_new_inode(struct inode * dir); extern void xiafs_free_inode(struct inode * inode); extern unsigned long xiafs_count_free_inodes(struct super_block *sb); diff -ur --new-file old/linux/include/net/ax25.h new/linux/include/net/ax25.h --- old/linux/include/net/ax25.h Sun Jun 9 11:25:41 1996 +++ new/linux/include/net/ax25.h Tue Aug 20 17:11:40 1996 @@ -126,7 +126,7 @@ #define AX25_DEF_N2 10 #define AX25_DEF_IDLE 20 #define AX25_DEF_PACLEN 256 -#define AX25_DEF_IPMAXQUEUE 1 /* 1 * ax25->window */ +#define AX25_DEF_IPMAXQUEUE 2 /* 1 * ax25->window */ #define AX25_DEF_DIGI (AX25_DIGI_INBAND|AX25_DIGI_XBAND) typedef struct ax25_uid_assoc { @@ -203,15 +203,13 @@ extern void dama_establish_data_link(ax25_cb *); /* ax25_route.c */ -extern void ax25_rt_rx_frame(ax25_address *, struct device *, ax25_digi *); extern int ax25_rt_get_info(char *, char **, off_t, int, int); extern int ax25_cs_get_info(char *, char **, off_t, int, int); extern int ax25_rt_autobind(ax25_cb *, ax25_address *); -extern void ax25_rt_build_path(ax25_cb *, ax25_address *); +extern void ax25_rt_build_path(ax25_cb *, ax25_address *, struct device *); extern void ax25_dg_build_path(struct sk_buff *, ax25_address *, struct device *); extern void ax25_rt_device_down(struct device *); extern int ax25_rt_ioctl(unsigned int, void *); -extern void ax25_ip_mode_set(ax25_address *, struct device *, char); extern char ax25_ip_mode_get(ax25_address *, struct device *); extern unsigned short ax25_dev_get_value(struct device *, int); extern void ax25_dev_device_up(struct device *); diff -ur --new-file old/linux/include/net/ip_forward.h new/linux/include/net/ip_forward.h --- old/linux/include/net/ip_forward.h Wed Feb 7 07:55:42 1996 +++ new/linux/include/net/ip_forward.h Fri Jul 19 07:24:05 1996 @@ -5,6 +5,7 @@ #define IPFWD_LASTFRAG 2 #define IPFWD_MASQUERADED 4 #define IPFWD_MULTICASTING 8 -#define IPFWD_MULTITUNNEL 16 +#define IPFWD_MULTITUNNEL 0x10 +#define IPFWD_NOTTLDEC 0x20 #endif diff -ur --new-file old/linux/include/net/netlink.h new/linux/include/net/netlink.h --- old/linux/include/net/netlink.h Sun Jun 9 11:29:14 1996 +++ new/linux/include/net/netlink.h Tue Aug 20 17:15:23 1996 @@ -2,8 +2,9 @@ #define __NET_NETLINK_H #define NET_MAJOR 36 /* Major 18 is reserved for networking */ -#define MAX_LINKS 10 /* 18,0 for route updates, 18,1 for SKIP, 18,2 debug tap 18,3 PPP reserved */ +#define MAX_LINKS 11 /* 18,0 for route updates, 18,1 for SKIP, 18,2 debug tap 18,3 PPP reserved */ /* 4-7 are psi0-psi3 8 is arpd 9 is ppp */ + /* 10 is for IPSEC */ #define MAX_QBYTES 32768 /* Maximum bytes in the queue */ #include @@ -21,6 +22,7 @@ #define NETLINK_PSI 4 /* PSI devices - 4 to 7 */ #define NETLINK_ARPD 8 #define NETLINK_NET_PPP 9 /* Non tty PPP devices */ +#define NETLINK_IPSEC 10 /* IPSEC */ #ifdef CONFIG_RTNETLINK extern void ip_netlink_msg(unsigned long, __u32, __u32, __u32, short, short, char *); diff -ur --new-file old/linux/include/net/netrom.h new/linux/include/net/netrom.h --- old/linux/include/net/netrom.h Thu Apr 18 13:35:33 1996 +++ new/linux/include/net/netrom.h Wed Aug 7 07:41:57 1996 @@ -64,10 +64,21 @@ struct sock *sk; /* Backlink to socket */ } nr_cb; +struct nr_neigh { + struct nr_neigh *next; + ax25_address callsign; + ax25_digi *digipeat; + struct device *dev; + unsigned char quality; + unsigned char locked; + unsigned short count; + unsigned int number; +}; + struct nr_route { - unsigned char quality; - unsigned char obs_count; - unsigned short neighbour; + unsigned char quality; + unsigned char obs_count; + struct nr_neigh *neighbour; }; struct nr_node { @@ -77,17 +88,6 @@ unsigned char which; unsigned char count; struct nr_route routes[3]; -}; - -struct nr_neigh { - struct nr_neigh *next; - ax25_address callsign; - ax25_digi *digipeat; - struct device *dev; - unsigned char quality; - unsigned char locked; - unsigned short count; - unsigned short number; }; /* af_netrom.c */ diff -ur --new-file old/linux/include/net/sock.h new/linux/include/net/sock.h --- old/linux/include/net/sock.h Thu Aug 29 16:32:46 1996 +++ new/linux/include/net/sock.h Thu Aug 29 16:33:33 1996 @@ -251,8 +251,8 @@ unsigned char max_ack_backlog; unsigned char priority; unsigned char debug; - unsigned long rcvbuf; - unsigned long sndbuf; + unsigned short rcvbuf; + unsigned short sndbuf; unsigned short type; unsigned char localroute; /* Route locally only */ #ifdef CONFIG_AX25 diff -ur --new-file old/linux/include/net/spx.h new/linux/include/net/spx.h --- old/linux/include/net/spx.h Thu Jan 1 01:00:00 1970 +++ new/linux/include/net/spx.h Thu Aug 1 14:43:05 1996 @@ -0,0 +1,38 @@ +#ifndef __NET_SPX_H +#define __NET_SPX_H + +/* + * Internal definitions for the SPX protocol. + */ + +/* + * The SPX header following an IPX header. + */ + +struct spxhdr +{ + __u8 cctl; +#define CCTL_SPXII_XHD 0x01 /* SPX2 extended header */ +#define CCTL_SPX_UNKNOWN 0x02 /* Unknown (unused ??) */ +#define CCTL_SPXII_NEG 0x04 /* Negotiate size */ +#define CCTL_SPXII 0x08 /* Set for SPX2 */ +#define CCTL_EOM 0x10 /* End of message marker */ +#define CCTL_URG 0x20 /* Urgent marker in SPP (not used in SPX?) */ +#define CCTL_ACK 0x40 /* Send me an ACK */ +#define CCTL_CTL 0x80 /* Control message */ + __u8 dtype; +#define SPX_DTYPE_ECONN 0xFE /* Finished */ +#define SPX_DTYPE_ECACK 0xFF /* Ok */ + __u16 sconn; /* Connection ID */ + __u16 dconn; /* Connection ID */ + __u16 sequence; + __u16 ackseq; + __u16 allocseq; +}; + +#define IPXTYPE_SPX 5 + + + + +#endif diff -ur --new-file old/linux/include/net/tcp.h new/linux/include/net/tcp.h --- old/linux/include/net/tcp.h Sun Jun 9 11:28:48 1996 +++ new/linux/include/net/tcp.h Tue Aug 20 17:14:55 1996 @@ -174,22 +174,6 @@ extern void tcp_delack_timer(unsigned long); extern void tcp_retransmit_timer(unsigned long); -/* - * Default sequence number picking algorithm. - * As close as possible to RFC 793, which - * suggests using a 250kHz clock. - * Further reading shows this assumes 2MB/s networks. - * For 10MB/s ethernet, a 1MHz clock is appropriate. - * That's funny, Linux has one built in! Use it! - */ - -static inline u32 tcp_init_seq(void) -{ - struct timeval tv; - do_gettimeofday(&tv); - return tv.tv_usec+tv.tv_sec*1000000; -} - static __inline__ int tcp_old_window(struct sock * sk) { return sk->window - (sk->acked_seq - sk->lastwin_seq); diff -ur --new-file old/linux/include/scsi/scsi.h new/linux/include/scsi/scsi.h --- old/linux/include/scsi/scsi.h Tue Jun 4 11:56:48 1996 +++ new/linux/include/scsi/scsi.h Mon Jul 8 12:09:16 1996 @@ -94,9 +94,10 @@ #define INTERMEDIATE_GOOD 0x08 #define INTERMEDIATE_C_GOOD 0x0a #define RESERVATION_CONFLICT 0x0c -#define QUEUE_FULL 0x1a +#define COMMAND_TERMINATED 0x11 +#define QUEUE_FULL 0x14 -#define STATUS_MASK 0x1e +#define STATUS_MASK 0x3e /* * SENSE KEYS diff -ur --new-file old/linux/ipc/shm.c new/linux/ipc/shm.c --- old/linux/ipc/shm.c Fri Apr 26 09:08:50 1996 +++ new/linux/ipc/shm.c Tue Jul 23 09:26:53 1996 @@ -467,6 +467,7 @@ int err; unsigned int id; unsigned long addr; + unsigned long len; if (shmid < 0) { /* printk("shmat() -> EINVAL because shmid = %d < 0\n",shmid); */ @@ -490,6 +491,12 @@ else return -EINVAL; } + /* + * Check if addr exceeds TASK_SIZE (from do_mmap) + */ + len = PAGE_SIZE*shp->shm_npages; + if (addr >= TASK_SIZE || len > TASK_SIZE || addr > TASK_SIZE - len) + return -EINVAL; /* * If shm segment goes below stack, make sure there is some * space left for the stack to grow (presently 4 pages). diff -ur --new-file old/linux/kernel/exit.c new/linux/kernel/exit.c --- old/linux/kernel/exit.c Mon Jun 3 11:26:38 1996 +++ new/linux/kernel/exit.c Fri Jul 5 12:48:39 1996 @@ -75,8 +75,8 @@ if (!p || sig > 32) return -EINVAL; if (!priv && ((sig != SIGCONT) || (current->session != p->session)) && - (current->euid ^ p->euid) && (current->euid ^ p->uid) && - (current->uid ^ p->euid) && (current->uid ^ p->uid) && + (current->euid ^ p->suid) && (current->euid ^ p->uid) && + (current->uid ^ p->suid) && (current->uid ^ p->uid) && !suser()) return -EPERM; if (!sig) @@ -346,12 +346,12 @@ * * "I ask you, have you ever known what it is to be an orphan?" */ -int is_orphaned_pgrp(int pgrp) +static int will_become_orphaned_pgrp(int pgrp, struct task_struct * ignored_task) { struct task_struct *p; for_each_task(p) { - if ((p->pgrp != pgrp) || + if ((p == ignored_task) || (p->pgrp != pgrp) || (p->state == TASK_ZOMBIE) || (p->p_pptr->pid == 1)) continue; @@ -362,6 +362,11 @@ return(1); /* (sighing) "Often!" */ } +int is_orphaned_pgrp(int pgrp) +{ + return will_become_orphaned_pgrp(pgrp, 0); +} + static inline int has_stopped_jobs(int pgrp) { struct task_struct * p; @@ -388,6 +393,26 @@ } } +static inline void close_files(struct files_struct * files) +{ + int i, j; + + j = 0; + for (;;) { + unsigned long set = files->open_fds.fds_bits[j]; + i = j * __NFDBITS; + j++; + if (i >= NR_OPEN) + break; + while (set) { + if (set & 1) + close_fp(files->fd[i]); + i++; + set >>= 1; + } + } +} + static inline void __exit_files(struct task_struct *tsk) { struct files_struct * files = tsk->files; @@ -395,14 +420,7 @@ if (files) { tsk->files = NULL; if (!--files->count) { - int i; - for (i=0 ; ifd[i]; - if (!filp) - continue; - files->fd[i] = NULL; - close_fp(filp); - } + close_files(files); kfree(files); } } @@ -495,7 +513,7 @@ */ if ((current->p_pptr->pgrp != current->pgrp) && (current->p_pptr->session == current->session) && - is_orphaned_pgrp(current->pgrp) && + will_become_orphaned_pgrp(current->pgrp, current) && has_stopped_jobs(current->pgrp)) { kill_pg(current->pgrp,SIGHUP,1); kill_pg(current->pgrp,SIGCONT,1); @@ -607,6 +625,9 @@ if (flag) return flag; } + if (options & ~(WNOHANG|WUNTRACED|__WCLONE)) + return -EINVAL; + add_wait_queue(¤t->wait_chldexit,&wait); repeat: flag=0; @@ -666,12 +687,11 @@ retval = 0; if (options & WNOHANG) goto end_wait4; - current->state=TASK_INTERRUPTIBLE; - schedule(); - current->signal &= ~(1<<(SIGCHLD-1)); retval = -ERESTARTSYS; if (current->signal & ~current->blocked) goto end_wait4; + current->state=TASK_INTERRUPTIBLE; + schedule(); goto repeat; } retval = -ECHILD; diff -ur --new-file old/linux/kernel/fork.c new/linux/kernel/fork.c --- old/linux/kernel/fork.c Mon Apr 22 12:08:47 1996 +++ new/linux/kernel/fork.c Thu Jul 4 19:09:41 1996 @@ -34,7 +34,6 @@ static inline int find_empty_process(void) { int i; - struct task_struct *p; if (nr_tasks >= NR_TASKS - MIN_TASKS_LEFT_FOR_ROOT) { if (current->uid) @@ -43,7 +42,9 @@ if (current->uid) { long max_tasks = current->rlim[RLIMIT_NPROC].rlim_cur; + max_tasks--; /* count the new process.. */ if (max_tasks < nr_tasks) { + struct task_struct *p; for_each_task (p) { if (p->uid == current->uid) if (--max_tasks < 0) @@ -159,22 +160,33 @@ static inline int copy_files(unsigned long clone_flags, struct task_struct * tsk) { int i; + struct files_struct *oldf, *newf; + struct file **old_fds, **new_fds; + oldf = current->files; if (clone_flags & CLONE_FILES) { - current->files->count++; + oldf->count++; return 0; } - tsk->files = kmalloc(sizeof(*tsk->files), GFP_KERNEL); - if (!tsk->files) + + newf = kmalloc(sizeof(*newf), GFP_KERNEL); + tsk->files = newf; + if (!newf) return -1; - tsk->files->count = 1; - memcpy(&tsk->files->close_on_exec, ¤t->files->close_on_exec, - sizeof(tsk->files->close_on_exec)); - for (i = 0; i < NR_OPEN; i++) { - struct file * f = current->files->fd[i]; + + newf->count = 1; + newf->close_on_exec = oldf->close_on_exec; + newf->open_fds = oldf->open_fds; + + old_fds = oldf->fd; + new_fds = newf->fd; + for (i = NR_OPEN; i != 0; i--) { + struct file * f = *old_fds; + old_fds++; + *new_fds = f; + new_fds++; if (f) f->f_count++; - tsk->files->fd[i] = f; } return 0; } diff -ur --new-file old/linux/kernel/ksyms.c new/linux/kernel/ksyms.c --- old/linux/kernel/ksyms.c Thu Aug 29 16:32:43 1996 +++ new/linux/kernel/ksyms.c Thu Aug 29 16:33:30 1996 @@ -45,6 +45,7 @@ #include #include #include +#include extern unsigned char aux_device_present, kbd_read_mask; @@ -79,7 +80,7 @@ extern void hard_reset_now(void); -#ifdef CONFIG_ATM_TCP +#ifdef CONFIG_ATM_TCP_MODULE extern int (*atmtcp_attach_hook)(struct socket *sock); #endif @@ -304,6 +305,7 @@ X(system_utsname), X(sys_call_table), X(hard_reset_now), + X(_ctype), /* Signal interfaces */ X(send_sig), @@ -340,6 +342,7 @@ X(insert_inode_hash), X(event), X(__down), + X(securelevel), /* all busmice */ X(add_mouse_randomness), X(fasync_helper), @@ -361,7 +364,7 @@ X(atm_dev_deregister), X(atm_find_ci), #endif -#ifdef CONFIG_ATM_TCP +#ifdef CONFIG_ATM_TCP_MODULE X(atmtcp_attach_hook), #endif diff -ur --new-file old/linux/kernel/sched.c new/linux/kernel/sched.c --- old/linux/kernel/sched.c Tue May 7 11:06:51 1996 +++ new/linux/kernel/sched.c Sun Aug 18 09:37:57 1996 @@ -573,6 +573,7 @@ { struct timer_list * timer; + cli(); while ((timer = timer_head.next) != &timer_head && timer->expires <= jiffies) { void (*fn)(unsigned long) = timer->function; unsigned long data = timer->data; @@ -583,6 +584,7 @@ fn(data); cli(); } + sti(); } static inline void run_old_timers(void) @@ -936,12 +938,18 @@ if (cpu == i) { utime = ticks-system; stime = system; - } else if (smp_proc_in_lock[i]) { + } else if (smp_proc_in_lock[j]) { utime = 0; stime = ticks; } update_one_process(p, ticks, utime, stime); + if (p->priority < DEF_PRIORITY) + kstat.cpu_nice += utime; + else + kstat.cpu_user += utime; + kstat.cpu_system += stime; + p->counter -= ticks; if (p->counter >= 0) continue; @@ -966,44 +974,34 @@ static unsigned long lost_ticks = 0; static unsigned long lost_ticks_system = 0; -static void timer_bh(void) +static inline void update_times(void) { - unsigned long ticks, system; - - run_old_timers(); + unsigned long ticks; - cli(); - run_timer_list(); - ticks = lost_ticks; - lost_ticks = 0; - system = lost_ticks_system; - lost_ticks_system = 0; - sti(); + ticks = xchg(&lost_ticks, 0); if (ticks) { + unsigned long system; + + system = xchg(&lost_ticks_system, 0); calc_load(ticks); update_wall_time(ticks); update_process_times(ticks, system); } } -/* - * Run the bottom half stuff only about 100 times a second, - * we'd just use up unnecessary CPU time for timer handling - * otherwise - */ -#if HZ > 100 -#define should_run_timers(x) ((x) >= HZ/100) -#else -#define should_run_timers(x) (1) -#endif +static void timer_bh(void) +{ + update_times(); + run_old_timers(); + run_timer_list(); +} void do_timer(struct pt_regs * regs) { (*(unsigned long *)&jiffies)++; lost_ticks++; - if (should_run_timers(lost_ticks)) - mark_bh(TIMER_BH); + mark_bh(TIMER_BH); if (!user_mode(regs)) { lost_ticks_system++; if (prof_buffer && current->pid) { @@ -1107,7 +1105,7 @@ if (increase) increment = -increment; newprio = current->priority - increment; - if (newprio < 1) + if ((signed) newprio < 1) newprio = 1; if (newprio > DEF_PRIORITY*2) newprio = DEF_PRIORITY*2; diff -ur --new-file old/linux/kernel/signal.c new/linux/kernel/signal.c --- old/linux/kernel/signal.c Sat Feb 17 08:19:43 1996 +++ new/linux/kernel/signal.c Tue Jul 2 18:08:43 1996 @@ -91,7 +91,7 @@ * POSIX 3.3.1.3: * "Setting a signal action to SIG_IGN for a signal that is pending * shall cause the pending signal to be discarded, whether or not - * it is blocked" (but SIGCHLD is unspecified: linux leaves it alone). + * it is blocked." * * "Setting a signal action to SIG_DFL for a signal that is pending * and whose default action is to ignore the signal (for example, @@ -108,8 +108,6 @@ p = signum - 1 + current->sig->action; if (p->sa_handler == SIG_IGN) { - if (signum == SIGCHLD) - return; current->signal &= ~_S(signum); return; } @@ -156,18 +154,14 @@ if (signum<1 || signum>32) return -EINVAL; - if (signum==SIGKILL || signum==SIGSTOP) - return -EINVAL; p = signum - 1 + current->sig->action; if (action) { int err = verify_area(VERIFY_READ, action, sizeof(*action)); if (err) return err; + if (signum==SIGKILL || signum==SIGSTOP) + return -EINVAL; memcpy_fromfs(&new_sa, action, sizeof(struct sigaction)); - new_sa.sa_mask |= _S(signum); - if (new_sa.sa_flags & SA_NOMASK) - new_sa.sa_mask &= ~_S(signum); - new_sa.sa_mask &= _BLOCKABLE; if (new_sa.sa_handler != SIG_DFL && new_sa.sa_handler != SIG_IGN) { err = verify_area(VERIFY_READ, new_sa.sa_handler, 1); if (err) diff -ur --new-file old/linux/kernel/sys.c new/linux/kernel/sys.c --- old/linux/kernel/sys.c Thu Jun 6 08:28:51 1996 +++ new/linux/kernel/sys.c Wed Jul 17 07:16:54 1996 @@ -634,8 +634,13 @@ asmlinkage int sys_setsid(void) { - if (current->leader) - return -EPERM; + struct task_struct * p; + + for_each_task(p) { + if (p->pgrp == current->pid) + return -EPERM; + } + current->leader = 1; current->session = current->pgrp = current->pid; current->tty = NULL; @@ -651,21 +656,29 @@ int i; int * groups; - if (gidsetsize) { - i = verify_area(VERIFY_WRITE, grouplist, sizeof(gid_t) * gidsetsize); - if (i) - return i; - } + if (gidsetsize < 0) + return -EINVAL; groups = current->groups; - for (i = 0 ; (i < NGROUPS) && (*groups != NOGROUP) ; i++, groups++) { - if (!gidsetsize) - continue; - if (i >= gidsetsize) + for (i = 0 ; i < NGROUPS ; i++) { + if (groups[i] == NOGROUP) break; - put_user(*groups, grouplist); - grouplist++; } - return(i); + if (gidsetsize) { + int error; + error = verify_area(VERIFY_WRITE, grouplist, sizeof(gid_t) * gidsetsize); + if (error) + return error; + if (i > gidsetsize) + return -EINVAL; + + for (i = 0 ; i < NGROUPS ; i++) { + if (groups[i] == NOGROUP) + break; + put_user(groups[i], grouplist); + grouplist++; + } + } + return i; } asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist) diff -ur --new-file old/linux/lib/ctype.c new/linux/lib/ctype.c --- old/linux/lib/ctype.c Mon Nov 27 14:53:48 1995 +++ new/linux/lib/ctype.c Tue Jul 2 18:08:43 1996 @@ -26,10 +26,11 @@ _L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */ -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 160-175 */ -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 176-191 */ -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 192-207 */ -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 208-223 */ -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 224-239 */ -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* 240-255 */ +_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */ +_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */ +_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */ +_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */ +_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */ +_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */ + diff -ur --new-file old/linux/mm/filemap.c new/linux/mm/filemap.c --- old/linux/mm/filemap.c Mon Jun 3 10:26:09 1996 +++ new/linux/mm/filemap.c Fri Aug 9 13:55:35 1996 @@ -78,7 +78,7 @@ page->prev = NULL; remove_page_from_hash_queue(page); page->inode = NULL; - free_page(page_address(page)); + __free_page(page); continue; } } @@ -111,15 +111,16 @@ page->prev = NULL; remove_page_from_hash_queue(page); page->inode = NULL; - free_page(page_address(page)); + __free_page(page); continue; } p = &page->next; offset = start - offset; /* partial truncate, clear end of page */ if (offset < PAGE_SIZE) { - memset((void *) (offset + page_address(page)), 0, PAGE_SIZE - offset); - flush_page_to_ram(page_address(page)); + unsigned long address = page_address(page); + memset((void *) (offset + address), 0, PAGE_SIZE - offset); + flush_page_to_ram(address); } } } @@ -175,7 +176,7 @@ if (page->inode) { remove_page_from_hash_queue(page); remove_page_from_inode_queue(page); - free_page(page_address(page)); + __free_page(page); return 1; } @@ -328,9 +329,9 @@ #endif /* - * Read-ahead profiling informations - * --------------------------------- - * Every PROFILE_MAXREADCOUNT, the following informations are written + * Read-ahead profiling information + * -------------------------------- + * Every PROFILE_MAXREADCOUNT, the following information is written * to the syslog: * Percentage of asynchronous read-ahead. * Average of read-ahead fields context value. @@ -415,7 +416,7 @@ * Reasonable means, in this context, not too large but not too small. * The actual maximum value is: * MAX_READAHEAD + PAGE_SIZE = 76k is CONFIG_READA_SMALL is undefined - * and 32K if defined. + * and 32K if defined (4K page size assumed). * * Asynchronous read-ahead benefits: * --------------------------------- @@ -442,15 +443,17 @@ * - The total memory pool usage for the file access stream. * This maximum memory usage is implicitly 2 IO read chunks: * 2*(MAX_READAHEAD + PAGE_SIZE) = 156K if CONFIG_READA_SMALL is undefined, - * 64k if defined. + * 64k if defined (4K page size assumed). */ -#if 0 /* small readahead */ -#define MAX_READAHEAD (PAGE_SIZE*7) -#define MIN_READAHEAD (PAGE_SIZE*2) -#else -#define MAX_READAHEAD (PAGE_SIZE*18) -#define MIN_READAHEAD (PAGE_SIZE*3) +#define PageAlignSize(size) (((size) + PAGE_SIZE -1) & PAGE_MASK) + +#if 0 /* small readahead */ +#define MAX_READAHEAD PageAlignSize(4096*7) +#define MIN_READAHEAD PageAlignSize(4096*2) +#else /* large readahead */ +#define MAX_READAHEAD PageAlignSize(4096*18) +#define MIN_READAHEAD PageAlignSize(4096*3) #endif static inline unsigned long generic_file_readahead(int reada_ok, struct file * filp, struct inode * inode, @@ -782,7 +785,8 @@ * Ok, found a page in the page cache, now we need to check * that it's up-to-date */ - wait_on_page(page); + if (PageLocked(page)) + goto page_locked_wait; if (!PageUptodate(page)) goto page_read_error; @@ -849,6 +853,11 @@ new_page = try_to_read_ahead(inode, offset + PAGE_SIZE, 0); goto found_page; +page_locked_wait: + __wait_on_page(page); + if (PageUptodate(page)) + goto success; + page_read_error: /* * Umm, take care of errors if the page isn't up-to-date. diff -ur --new-file old/linux/mm/memory.c new/linux/mm/memory.c --- old/linux/mm/memory.c Thu May 16 14:15:36 1996 +++ new/linux/mm/memory.c Wed Aug 14 09:28:06 1996 @@ -298,10 +298,8 @@ return error; } -static inline void forget_pte(pte_t page) +static inline void free_pte(pte_t page) { - if (pte_none(page)) - return; if (pte_present(page)) { unsigned long addr = pte_page(page); if (addr >= high_memory || PageReserved(mem_map+MAP_NR(addr))) @@ -315,10 +313,17 @@ swap_free(pte_val(page)); } +static inline void forget_pte(pte_t page) +{ + if (!pte_none(page)) { + printk("forget_pte: old mapping existed!\n"); + free_pte(page); + } +} + static inline void zap_pte_range(pmd_t * pmd, unsigned long address, unsigned long size) { pte_t * pte; - unsigned long end; if (pmd_none(*pmd)) return; @@ -329,16 +334,21 @@ } pte = pte_offset(pmd, address); address &= ~PMD_MASK; - end = address + size; - if (end >= PMD_SIZE) - end = PMD_SIZE; - do { - pte_t page = *pte; - pte_clear(pte); - forget_pte(page); - address += PAGE_SIZE; + if (address + size > PMD_SIZE) + size = PMD_SIZE - address; + size >>= PAGE_SHIFT; + for (;;) { + pte_t page; + if (!size) + break; + page = *pte; pte++; - } while (address < end); + size--; + if (pte_none(page)) + continue; + pte_clear(pte-1); + free_pte(page); + } } static inline void zap_pmd_range(pgd_t * dir, unsigned long address, unsigned long size) @@ -524,7 +534,6 @@ static void put_page(pte_t * page_table, pte_t pte) { if (!pte_none(*page_table)) { - printk("put_page: page already exists %08lx\n", pte_val(*page_table)); free_page(pte_page(pte)); return; } @@ -746,26 +755,6 @@ return -EFAULT; } -static inline void get_empty_page(struct task_struct * tsk, struct vm_area_struct * vma, - pte_t * page_table, int write_access) -{ - pte_t pte; - - pte = pte_wrprotect(mk_pte(ZERO_PAGE, vma->vm_page_prot)); - if (write_access) { - unsigned long page = get_free_page(GFP_KERNEL); - pte = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))); - vma->vm_mm->rss++; - tsk->min_flt++; - if (!page) { - oom(tsk); - pte = BAD_PAGE; - } - flush_page_to_ram(page); - } - put_page(page_table, pte); -} - /* * This function zeroes out partial mmap'ed pages at truncation time.. */ @@ -845,28 +834,6 @@ } while ((mpnt = mpnt->vm_next_share) != inode->i_mmap); } -/* - * fill in an empty page-table if none exists. - */ -static inline pte_t * get_empty_pgtable(struct task_struct * tsk,unsigned long address) -{ - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - - pgd = pgd_offset(tsk->mm, address); - pmd = pmd_alloc(pgd, address); - if (!pmd) { - oom(tsk); - return NULL; - } - pte = pte_alloc(pmd, address); - if (!pte) { - oom(tsk); - return NULL; - } - return pte; -} static inline void do_swap_page(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long address, @@ -898,45 +865,45 @@ * tries to share with existing pages, but makes a separate copy if * the "write_access" parameter is true in order to avoid the next * page fault. + * + * As this is called only for pages that do not currently exist, we + * do not need to flush old virtual caches or the TLB. */ void do_no_page(struct task_struct * tsk, struct vm_area_struct * vma, unsigned long address, int write_access) { + pgd_t * pgd; + pmd_t * pmd; pte_t * page_table; pte_t entry; unsigned long page; - page_table = get_empty_pgtable(tsk, address); + pgd = pgd_offset(tsk->mm, address); + pmd = pmd_alloc(pgd, address); + if (!pmd) + goto no_memory; + page_table = pte_alloc(pmd, address); if (!page_table) - return; + goto no_memory; entry = *page_table; if (pte_present(entry)) - return; - if (!pte_none(entry)) { - do_swap_page(tsk, vma, address, page_table, entry, write_access); - return; - } + goto is_present; + if (!pte_none(entry)) + goto swap_page; address &= PAGE_MASK; - if (!vma->vm_ops || !vma->vm_ops->nopage) { - flush_cache_page(vma, address); - get_empty_page(tsk, vma, page_table, write_access); - return; - } - ++tsk->maj_flt; - ++vma->vm_mm->rss; + if (!vma->vm_ops || !vma->vm_ops->nopage) + goto anonymous_page; /* * The third argument is "no_share", which tells the low-level code * to copy, not share the page even if sharing is possible. It's * essentially an early COW detection */ - page = vma->vm_ops->nopage(vma, address, write_access && !(vma->vm_flags & VM_SHARED)); - if (!page) { - force_sig(SIGBUS, current); - flush_cache_page(vma, address); - put_page(page_table, BAD_PAGE); - flush_tlb_page(vma, address); - return; - } + page = vma->vm_ops->nopage(vma, address, + (vma->vm_flags & VM_SHARED)?0:write_access); + if (!page) + goto sigbus; + ++tsk->maj_flt; + ++vma->vm_mm->rss; /* * This silly early PAGE_DIRTY setting removes a race * due to the bad i386 page protection. But it's valid @@ -953,9 +920,39 @@ entry = pte_mkwrite(pte_mkdirty(entry)); } else if (mem_map[MAP_NR(page)].count > 1 && !(vma->vm_flags & VM_SHARED)) entry = pte_wrprotect(entry); - flush_cache_page(vma, address); put_page(page_table, entry); - flush_tlb_page(vma, address); + /* no need to invalidate: a not-present page shouldn't be cached */ + return; + +anonymous_page: + entry = pte_wrprotect(mk_pte(ZERO_PAGE, vma->vm_page_prot)); + if (write_access) { + unsigned long page = __get_free_page(GFP_KERNEL); + if (!page) + goto sigbus; + memset((void *) page, 0, PAGE_SIZE); + entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot))); + vma->vm_mm->rss++; + tsk->min_flt++; + flush_page_to_ram(page); + } + put_page(page_table, entry); + return; + +sigbus: + force_sig(SIGBUS, current); + put_page(page_table, BAD_PAGE); + /* no need to invalidate, wasn't present */ + return; + +swap_page: + do_swap_page(tsk, vma, address, page_table, entry, write_access); + return; + +no_memory: + oom(tsk); +is_present: + return; } /* diff -ur --new-file old/linux/mm/mmap.c new/linux/mm/mmap.c --- old/linux/mm/mmap.c Thu Jun 6 08:29:59 1996 +++ new/linux/mm/mmap.c Wed Jul 31 14:58:59 1996 @@ -823,7 +823,7 @@ * If the one of the segments is only being partially unmapped, * it will put new vm_area_struct(s) into the address space. */ - while (free) { + do { unsigned long st, end; mpnt = free; @@ -840,9 +840,10 @@ zap_page_range(current->mm, st, end-st); unmap_fixup(mpnt, st, end-st); kfree(mpnt); - } + } while (free); + + /* we could zap the page tables here too.. */ - zap_page_range(current->mm, addr, len); return 0; } diff -ur --new-file old/linux/mm/mremap.c new/linux/mm/mremap.c --- old/linux/mm/mremap.c Wed May 29 13:50:19 1996 +++ new/linux/mm/mremap.c Wed Jun 26 08:44:52 1996 @@ -167,8 +167,6 @@ return -EINVAL; old_len = PAGE_ALIGN(old_len); new_len = PAGE_ALIGN(new_len); - if (old_len == new_len) - return addr; /* * Always allow a shrinking remap: that just unmaps @@ -196,7 +194,8 @@ } /* old_len exactly to the end of the area.. */ - if (old_len == vma->vm_end - addr) { + if (old_len == vma->vm_end - addr && + (old_len != new_len || !(flags & MREMAP_MAYMOVE))) { unsigned long max_addr = TASK_SIZE; if (vma->vm_next) max_addr = vma->vm_next->vm_start; diff -ur --new-file old/linux/mm/page_alloc.c new/linux/mm/page_alloc.c --- old/linux/mm/page_alloc.c Mon Jun 3 11:27:05 1996 +++ new/linux/mm/page_alloc.c Sat Aug 10 08:59:52 1996 @@ -36,30 +36,34 @@ #define NR_MEM_LISTS 6 +/* The start of this MUST match the start of "struct page" */ struct free_area_struct { - struct page list; + struct page *next; + struct page *prev; unsigned int * map; }; +#define memory_head(x) ((struct page *)(x)) + static struct free_area_struct free_area[NR_MEM_LISTS]; -static inline void init_mem_queue(struct page * head) +static inline void init_mem_queue(struct free_area_struct * head) { - head->next = head; - head->prev = head; + head->next = memory_head(head); + head->prev = memory_head(head); } -static inline void add_mem_queue(struct page * head, struct page * entry) +static inline void add_mem_queue(struct free_area_struct * head, struct page * entry) { struct page * next = head->next; - entry->prev = head; + entry->prev = memory_head(head); entry->next = next; next->prev = entry; head->next = entry; } -static inline void remove_mem_queue(struct page * head, struct page * entry) +static inline void remove_mem_queue(struct page * entry) { struct page * next = entry->next; struct page * prev = entry->prev; @@ -85,9 +89,12 @@ /* * Buddy system. Hairy. You really aren't expected to understand this + * + * Hint: -mask = 1+~mask */ static inline void free_pages_ok(unsigned long map_nr, unsigned long order) { + struct free_area_struct *area = free_area + order; unsigned long index = map_nr >> (1 + order); unsigned long mask = (~0UL) << order; unsigned long flags; @@ -98,23 +105,32 @@ #define list(x) (mem_map+(x)) map_nr &= mask; - nr_free_pages += 1 << order; - while (order < NR_MEM_LISTS-1) { - if (!change_bit(index, free_area[order].map)) + nr_free_pages -= mask; + while (mask + (1 << (NR_MEM_LISTS-1))) { + if (!change_bit(index, area->map)) break; - remove_mem_queue(&free_area[order].list, list(map_nr ^ (1+~mask))); + remove_mem_queue(list(map_nr ^ -mask)); mask <<= 1; - order++; + area++; index >>= 1; map_nr &= mask; } - add_mem_queue(&free_area[order].list, list(map_nr)); + add_mem_queue(area, list(map_nr)); #undef list restore_flags(flags); } +void __free_page(struct page *page) +{ + if (!PageReserved(page) && atomic_dec_and_test(&page->count)) { + unsigned long map_nr = page->map_nr; + delete_from_swap_cache(map_nr); + free_pages_ok(map_nr, 0); + } +} + void free_pages(unsigned long addr, unsigned long order) { unsigned long map_nr = MAP_NR(addr); @@ -141,8 +157,8 @@ #define RMQUEUE(order, dma) \ do { struct free_area_struct * area = free_area+order; \ unsigned long new_order = order; \ - do { struct page *prev = &area->list, *ret; \ - while (&area->list != (ret = prev->next)) { \ + do { struct page *prev = memory_head(area), *ret; \ + while (memory_head(area) != (ret = prev->next)) { \ if (!dma || CAN_DMA(ret)) { \ unsigned long map_nr = ret->map_nr; \ (prev->next = ret->next)->prev = prev; \ @@ -162,7 +178,7 @@ do { unsigned long size = 1 << high; \ while (high > low) { \ area--; high--; size >>= 1; \ - add_mem_queue(&area->list, map); \ + add_mem_queue(area, map); \ MARK_USED(index, high, area); \ index += size; \ map += size; \ @@ -219,7 +235,7 @@ for (order=0 ; order < NR_MEM_LISTS; order++) { struct page * tmp; unsigned long nr = 0; - for (tmp = free_area[order].list.next ; tmp != &free_area[order].list ; tmp = tmp->next) { + for (tmp = free_area[order].next ; tmp != memory_head(free_area+order) ; tmp = tmp->next) { nr ++; } total += nr * ((PAGE_SIZE>>10) << order); @@ -269,7 +285,7 @@ for (i = 0 ; i < NR_MEM_LISTS ; i++) { unsigned long bitmap_size; - init_mem_queue(&free_area[i].list); + init_mem_queue(free_area+i); mask += mask; end_mem = (end_mem + ~mask) & mask; bitmap_size = (end_mem - PAGE_OFFSET) >> (PAGE_SHIFT + i); diff -ur --new-file old/linux/mm/swapfile.c new/linux/mm/swapfile.c --- old/linux/mm/swapfile.c Tue May 28 06:39:18 1996 +++ new/linux/mm/swapfile.c Tue Jun 11 12:00:11 1996 @@ -16,6 +16,7 @@ #include #include #include +#include /* for blk_size */ #include #include /* for cli()/sti() */ @@ -457,7 +458,9 @@ if(error) goto bad_swap_2; error = -ENODEV; - if (!p->swap_device) + if (!p->swap_device || + (blk_size[MAJOR(p->swap_device)] && + !blk_size[MAJOR(p->swap_device)][MINOR(p->swap_device)])) goto bad_swap; error = -EBUSY; for (i = 0 ; i < nr_swapfiles ; i++) { diff -ur --new-file old/linux/mm/vmalloc.c new/linux/mm/vmalloc.c --- old/linux/mm/vmalloc.c Wed Apr 3 09:59:33 1996 +++ new/linux/mm/vmalloc.c Sun Aug 4 12:39:07 1996 @@ -306,7 +306,7 @@ void * addr; struct vm_struct * area; - if (offset < high_memory) + if (MAP_NR(offset) < MAP_NR(high_memory)) return NULL; if (offset & ~PAGE_MASK) return NULL; diff -ur --new-file old/linux/mm/vmscan.c new/linux/mm/vmscan.c --- old/linux/mm/vmscan.c Wed Jun 5 13:36:35 1996 +++ new/linux/mm/vmscan.c Tue Aug 13 14:00:33 1996 @@ -109,7 +109,7 @@ if (page_map->count != 1) return 0; if (!(entry = get_swap_page())) - return 0; + return -1; /* Aieee!!! Out of swap space! */ vma->vm_mm->rss--; flush_cache_page(vma, address); set_pte(page_table, __pte(entry)); @@ -312,6 +312,8 @@ if (!--p->swap_cnt) swap_task++; switch (swap_out_process(p, dma, wait)) { + case -1: + return 0; case 0: if (p->swap_cnt) swap_task++; @@ -404,6 +406,7 @@ while (1) { kswapd_awake = 0; current->signal = 0; + run_task_queue(&tq_disk); interruptible_sleep_on(&kswapd_wait); kswapd_awake = 1; swapstats.wakeups++; @@ -425,7 +428,6 @@ if (!kswapd_awake && kswapd_ctl.maxpages > 0) { wake_up(&kswapd_wait); need_resched = 1; - kswapd_awake = 1; } next_swap_jiffies = jiffies + swapout_interval; } diff -ur --new-file old/linux/net/Config.in new/linux/net/Config.in --- old/linux/net/Config.in Thu Aug 29 16:32:43 1996 +++ new/linux/net/Config.in Thu Aug 29 16:33:30 1996 @@ -20,9 +20,9 @@ bool 'AX.25 over Ethernet' CONFIG_BPQETHER bool 'Amateur Radio NET/ROM' CONFIG_NETROM fi -#if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then -# bool 'Bridging (EXPERIMENTAL)' CONFIG_BRIDGE -#fi +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'Bridging (EXPERIMENTAL)' CONFIG_BRIDGE +fi bool 'Kernel/User network link driver' CONFIG_NETLINK if [ "$CONFIG_NETLINK" = "y" ]; then bool 'Routing messages' CONFIG_RTNETLINK diff -ur --new-file old/linux/net/Makefile new/linux/net/Makefile --- old/linux/net/Makefile Thu Aug 29 16:32:44 1996 +++ new/linux/net/Makefile Thu Aug 29 16:33:31 1996 @@ -7,7 +7,7 @@ # # Note 2! The CFLAGS definition is now in the main makefile... -MOD_SUB_DIRS := ipv4 +MOD_SUB_DIRS := ipv4 atm ALL_SUB_DIRS := 802 atm ax25 bridge core ethernet ipv4 ipx unix appletalk \ netrom #decnet SUB_DIRS := core ethernet unix diff -ur --new-file old/linux/net/atm/atmarp.c new/linux/net/atm/atmarp.c --- old/linux/net/atm/atmarp.c Thu Aug 29 16:32:45 1996 +++ new/linux/net/atm/atmarp.c Thu Aug 29 16:33:31 1996 @@ -72,6 +72,7 @@ { struct atmarp_ctrl *ctrl; + atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse); ctrl = (struct atmarp_ctrl *) skb->data; if (ctrl->magic != ATMARP_CTRL_MAGIC) { printk(KERN_ALERT "atmarpd_send: bad magic 0x%x\n", diff -ur --new-file old/linux/net/atm/common.c new/linux/net/atm/common.c --- old/linux/net/atm/common.c Thu Aug 29 16:32:45 1996 +++ new/linux/net/atm/common.c Thu Aug 29 16:33:31 1996 @@ -50,7 +50,8 @@ { struct sk_buff *skb; - if (size+vcc->tx_inuse+ATM_PDU_OVHD > vcc->tx_quota) return NULL; + if (vcc->tx_inuse && size+vcc->tx_inuse+ATM_PDU_OVHD > vcc->tx_quota) + return NULL; while (!(skb = alloc_skb(size,GFP_KERNEL))) schedule(); DPRINTK("AlTx %d += %d\n",vcc->tx_inuse,skb->truesize); atomic_add(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse); diff -ur --new-file old/linux/net/atm/lec.c new/linux/net/atm/lec.c --- old/linux/net/atm/lec.c Thu Aug 29 16:32:46 1996 +++ new/linux/net/atm/lec.c Thu Aug 29 16:33:32 1996 @@ -22,15 +22,19 @@ #include "lec.h" #include "lec_arpc.h" +#include "tunable.h" #define DPRINTK(format,args...) +/* +#define DPRINTK printk +*/ struct atm_vcc *lecd = NULL; #define DUMP_PACKETS 0 /* 0 = None, - * 1 = 30 first bytes - * 2 = Whole packet - */ + * 1 = 30 first bytes + * 2 = Whole packet + */ static int lec_open(struct device *dev); static int lec_send_packet(struct sk_buff *skb, struct device *dev); @@ -89,6 +93,7 @@ struct lec_priv *priv = (struct lec_priv *)dev->priv; struct lecdatahdr_8023 *lec_h; struct atm_vcc *send_vcc; + unsigned char *nb; #if DUMP_PACKETS > 0 char buf[300]; int i=0; @@ -154,21 +159,43 @@ #endif /* DUMP_PACKETS > 0 */ /* Send to right vcc */ send_vcc = lec_arp_resolve(lec_h->h_dest); + DPRINTK("send_vcc:%p vcc_flags:%x\n", + send_vcc, send_vcc?send_vcc->flags:0); if (!send_vcc || !(send_vcc->flags & ATM_VF_READY)) { if (priv) priv->stats.tx_errors++; + /* DPRINTK("LEC:lec_send_packet: dropping ..\n"); dev_kfree_skb(skb, FREE_WRITE); return 0; + */ + DPRINTK("LEC:lec_send_packet: handing back...\n"); + dev->tbusy=1; + return 1; } else { #if DUMP_PACKETS > 0 printk("LEC:sending to vpi:%d vci:%d\n", send_vcc->vpi, send_vcc->vci); #endif /* DUMP_PACKETS > 0 */ /* Minimum ethernet-frame size */ - if (skb->len <62) - skb->len = 62; - atomic_add(skb->truesize,&send_vcc->tx_inuse); + if (skb->len <62) { + if (skb->truesize < 62) { + printk("LEC:data packet %ld / %d\n", + skb->len,skb->truesize); + nb=(unsigned char*)kmalloc(64, + GFP_ATOMIC); + memcpy(nb,skb->data,skb->len); + kfree(skb->head); + skb->head = skb->data = nb; + skb->tail = nb+62; + skb->end = nb+64; + skb->len=62; + skb->truesize = 64; + } else { + skb->len = 62; + } + } + atomic_add(skb->truesize, &send_vcc->tx_inuse); skb->atm.iovcnt = 0; send_vcc->dev->ops->send(send_vcc, skb); if (priv) @@ -310,8 +337,10 @@ struct lec_priv *priv = (struct lec_priv *)dev_lec.priv; struct atmlec_msg *mesg; int i; - + + atomic_sub(skb->truesize+ATM_PDU_OVHD, &vcc->tx_inuse); mesg = (struct atmlec_msg *)skb->data; + DPRINTK("LEC: msg from zeppelin:%d\n", mesg->type); switch(mesg->type) { case l_set_mac_addr: for (i=0;i<6;i++) { @@ -379,14 +408,6 @@ lec_arp_destroy(); -#if 0 - unregister_netdev(&dev_lec); - /* Should we do this? */ - if (priv) { - kfree_s(priv, sizeof(struct lec_priv)); - dev_lec.priv = NULL; - } -#endif if (skb_peek(&vcc->recvq)) printk("LEC lec_atm_close: closing with messages pending\n"); while ((skb = skb_dequeue(&vcc->recvq))) @@ -443,6 +464,7 @@ if (atm_addr) memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN); + atomic_add(skb->truesize+ATM_PDU_OVHD, &lecd->rx_inuse); skb_queue_tail(&lecd->recvq, skb); wake_up(&lecd->sleep); return 0; @@ -515,6 +537,7 @@ #endif /* DUMP_PACKETS > 0 */ if (memcmp(skb->data, lec_ctrl_magic, 4) ==0) { /* Control frame, to daemon*/ DPRINTK("LEC: To daemon\n"); + atomic_add(skb->truesize+ATM_PDU_OVHD, &vcc->rx_inuse); skb_queue_tail(&vcc->recvq, skb); wake_up(&vcc->sleep); } else { /* Data frame, queue to protocol handlers */ diff -ur --new-file old/linux/net/atm/lec_arpc.c new/linux/net/atm/lec_arpc.c --- old/linux/net/atm/lec_arpc.c Thu Aug 29 16:32:46 1996 +++ new/linux/net/atm/lec_arpc.c Thu Aug 29 16:33:33 1996 @@ -10,7 +10,11 @@ #include "lec.h" #include "lec_arpc.h" + #define DPRINTK(format,args...) +/* +#define DPRINTK printk +*/ #define DEBUG_ARP_TABLE 0 struct lec_arp_table *lec_arp_tables[LEC_ARP_TABLE_SIZE] = @@ -214,7 +218,7 @@ 0xff&to_remove->mac_addr[2], 0xff&to_remove->mac_addr[3], 0xff&to_remove->mac_addr[4], 0xff&to_remove->mac_addr[5]); - dump_arp_table(); + dump_arp_table(); return 0; } @@ -424,7 +428,7 @@ entry->next = to_remove->next; } lec_arp_clear_vccs(to_remove); - kfree_s(to_remove, sizeof(struct lec_arp_table)); + kfree(to_remove); } /* @@ -453,7 +457,7 @@ del_timer(&lec_arp_timer); - DPRINTK("lec_arp_check_expire\n"); + DPRINTK("lec_arp_check_expire %d\n",lec_arp_lock_var); if (!lec_arp_lock_var) { lec_arp_lock(); now = jiffies; @@ -465,6 +469,8 @@ else time_to_check = lec_aging_time; + DPRINTK("About to expire: %lx - %lx > %lx\n", + now,entry->last_used, time_to_check); if((now-entry->last_used > time_to_check) && !(entry->flags & LEC_PERMANENT_FLAG)) { /* Remove entry */ @@ -472,8 +478,7 @@ del_timer(&entry->timer); next = entry->next; lec_arp_remove(entry); - kfree_s(entry, - sizeof(struct lec_arp_table)); + kfree(entry); entry = next; } else { /* Something else */ @@ -521,7 +526,7 @@ for(entry =lec_arp_tables[i];entry != NULL; entry=next) { next = entry->next; lec_arp_remove(entry); - kfree_s(entry, sizeof(struct lec_arp_table)); + kfree(entry); } } entry = lec_arp_empty_ones; @@ -529,7 +534,7 @@ next = entry->next; del_timer(&entry->timer); lec_arp_clear_vccs(entry); - kfree_s(entry, sizeof(struct lec_arp_table)); + kfree(entry); entry = next; } lec_arp_empty_ones = NULL; @@ -538,7 +543,7 @@ next = entry->next; del_timer(&entry->timer); lec_arp_clear_vccs(entry); - kfree_s(entry, sizeof(struct lec_arp_table)); + kfree(entry); entry = next; } lec_no_forward = NULL; @@ -565,7 +570,7 @@ next = entry->next; if (!(entry->flags & LEC_PERMANENT_FLAG)) { lec_arp_remove(entry); - kfree_s(entry, sizeof(struct lec_arp_table)); + kfree(entry); } } } @@ -608,7 +613,8 @@ frame count is greater than the limit. If the limit has not been reached, allow the caller to send packet to BUS. */ - if (entry->packets_flooded < lec_maximum_unknown_frame_count) { + if (entry->status != ESI_FLUSH_PENDING && + entry->packets_flooded < lec_maximum_unknown_frame_count) { entry->packets_flooded++; DPRINTK("LEC_ARP: Flooding..\n"); return mcast_vcc; @@ -670,9 +676,10 @@ next = entry->next; if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN) && (permanent || - !(entry->flags & LEC_PERMANENT_FLAG))) + !(entry->flags & LEC_PERMANENT_FLAG))) { lec_arp_remove(entry); - kfree_s(entry, sizeof(struct lec_arp_table)); + kfree(entry); + } lec_arp_unlock(); return 0; } @@ -692,8 +699,11 @@ struct lec_arp_table *entry, *tmp; int i; + DPRINTK("LEC:lec_arp_update mac:%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n", + mac_addr[0],mac_addr[1],mac_addr[2],mac_addr[3], + mac_addr[4],mac_addr[5]); + dump_arp_table(); lec_arp_lock(); - if (lec_arp_empty_ones) { entry = lec_arp_empty_ones; if (!memcmp(entry->atm_addr, atm_addr, ATM_ESA_LEN)) { @@ -719,7 +729,7 @@ memcpy(tmp->atm_addr, atm_addr, ATM_ESA_LEN); tmp->vcc = entry->vcc; tmp->old_push = entry->old_push; - kfree_s(entry, sizeof(struct lec_arp_table)); + kfree(entry); entry=tmp; } else { entry->status = ESI_FORWARD_DIRECT; @@ -731,13 +741,14 @@ else entry->flags&=~LEC_REMOTE_FLAG; lec_arp_unlock(); + DPRINTK("After update\n"); + dump_arp_table(); return; } } entry = lec_arp_find(mac_addr); if (!entry) { entry = make_entry(mac_addr); - memcpy(entry->atm_addr, atm_addr, ATM_ESA_LEN); entry->status = ESI_UNKNOWN; lec_arp_put(entry); /* Temporary, changes before end of function */ @@ -772,6 +783,8 @@ entry->status = ESI_VC_PENDING; send_to_lecd(l_svc_setup, NULL, atm_addr); } + DPRINTK("After update2\n"); + dump_arp_table(); lec_arp_unlock(); } @@ -826,7 +839,8 @@ entry->timer.function = lec_arp_expire_vcc; entry->next = lec_no_forward; lec_no_forward = entry; - lec_arp_unlock(); + lec_arp_unlock(); + dump_arp_table(); return; } DPRINTK("LEC_ARP:Attaching data direct, default:%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n", @@ -847,7 +861,7 @@ DPRINTK("LEC_ARP: Attaching data direct\n"); DPRINTK("Currently -> Vcc: %d, Rvcc:%d\n", entry->vcc?entry->vcc->vci:0, - entry->recv_vcc?entry->recv_vcc:0); + entry->recv_vcc?entry->recv_vcc->vci:0); found_entry=1; del_timer(&entry->timer); if (vcc) { @@ -884,6 +898,7 @@ } if (found_entry) { lec_arp_unlock(); + DPRINTK("After vcc was added\n"); dump_arp_table(); return; } @@ -901,6 +916,8 @@ entry->timer.function = lec_arp_expire_vcc; add_timer(&entry->timer); lec_arp_unlock(); + DPRINTK("After vcc was added\n"); + dump_arp_table(); } void @@ -909,11 +926,15 @@ struct lec_arp_table *entry; int i; + DPRINTK("LEC:lec_flush_complete\n"); for (i=0;inext) { if (memcmp(atm_addr, entry->atm_addr,ATM_ESA_LEN)==0 && entry->flush_tran_id == tran_id) { + DPRINTK("entry->status:%d\n",entry->status); entry->status = ESI_FORWARD_DIRECT; + DPRINTK("LEC_ARP: Flushed\n"); + dump_arp_table(); return; } } @@ -944,6 +965,7 @@ printk("LEC_ARP: Set_flush_tran_id: entry not found\n"); return; } + DPRINTK("LEC: flush_tran_id:%lx\n",tran_id); entry->flush_tran_id = tran_id; } @@ -996,7 +1018,7 @@ next = entry->next; if (vcc == entry->vcc) { lec_arp_remove(entry); - kfree_s(entry, sizeof(struct lec_arp_table)); + kfree(entry); if (mcast_vcc == vcc) { mcast_vcc = NULL; } @@ -1004,6 +1026,7 @@ /* Bus distribution closed */ mcast_vcc = NULL; lec_arp_remove(entry); + kfree(entry); lec_arp_unlock(); vcc->push(vcc, NULL); return; @@ -1014,7 +1037,7 @@ while(entry && entry->vcc==vcc) { lec_arp_clear_vccs(entry); lec_arp_empty_ones=entry->next; - kfree_s(entry, sizeof(struct lec_arp_table)); + kfree(entry); entry=lec_arp_empty_ones; } for(;entry!=NULL;entry=next) { @@ -1022,14 +1045,14 @@ if (vcc == next->vcc) { lec_arp_clear_vccs(next); entry->next = next->next; - kfree_s(next, sizeof(struct lec_arp_table)); + kfree(next); } } entry=lec_no_forward; while(entry && entry->recv_vcc==vcc) { lec_arp_clear_vccs(entry); lec_no_forward=entry->next; - kfree_s(entry, sizeof(struct lec_arp_table)); + kfree(entry); entry=lec_no_forward; } for(;entry!=NULL;entry=next) { @@ -1037,10 +1060,11 @@ if (vcc == next->recv_vcc) { lec_arp_clear_vccs(next); entry->next = next->next; - kfree_s(next, sizeof(struct lec_arp_table)); + kfree(next); } - } + } lec_arp_unlock(); + dump_arp_table(); } void @@ -1055,11 +1079,12 @@ del_timer(&entry->timer); memcpy(entry->mac_addr, hdr->h_source, ETH_ALEN); entry->status = ESI_FORWARD_DIRECT; + entry->last_used = jiffies; lec_arp_empty_ones = entry->next; /* We might have got an entry */ if ((prev=lec_arp_find(hdr->h_source))) { lec_arp_remove(prev); - kfree_s(prev, sizeof(struct lec_arp_table)); + kfree(prev); } lec_arp_put(entry); lec_arp_unlock(); @@ -1079,10 +1104,11 @@ del_timer(&entry->timer); memcpy(entry->mac_addr, hdr->h_source, ETH_ALEN); entry->status = ESI_FORWARD_DIRECT; + entry->last_used = jiffies; prev->next = entry->next; if ((prev = lec_arp_find(hdr->h_source))) { lec_arp_remove(prev); - kfree_s(prev, sizeof(struct lec_arp_table)); + kfree(prev); } lec_arp_put(entry); lec_arp_unlock(); diff -ur --new-file old/linux/net/atm/signaling.c new/linux/net/atm/signaling.c --- old/linux/net/atm/signaling.c Thu Aug 29 16:32:45 1996 +++ new/linux/net/atm/signaling.c Thu Aug 29 16:33:31 1996 @@ -39,6 +39,7 @@ struct atmsvc_msg *msg; msg = (struct atmsvc_msg *) skb->data; + atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->tx_inuse); DPRINTK("sigd_send %d (0x%lx)\n",(int) msg->type,msg->vcc); vcc = (struct atm_vcc *) msg->vcc; switch (msg->type) { diff -ur --new-file old/linux/net/atm/svc.c new/linux/net/atm/svc.c --- old/linux/net/atm/svc.c Thu Aug 29 16:32:45 1996 +++ new/linux/net/atm/svc.c Thu Aug 29 16:33:31 1996 @@ -292,6 +292,7 @@ old_vcc->backlog_quota++; if (!new_vcc->reply) break; dev_kfree_skb(skb,FREE_WRITE); + if (new_vcc->reply != -ERESTARTSYS) return new_vcc->reply; } if (!sigd) return -EUNATCH; msg = (struct atmsvc_msg *) skb->data; diff -ur --new-file old/linux/net/ax25/af_ax25.c new/linux/net/ax25/af_ax25.c --- old/linux/net/ax25/af_ax25.c Fri May 31 12:46:27 1996 +++ new/linux/net/ax25/af_ax25.c Wed Aug 7 07:41:57 1996 @@ -1,5 +1,5 @@ /* - * AX.25 release 031 + * AX.25 release 032 * * This is ALPHA test software. This code may break your machine, randomly fail to work with new * releases, misbehave and/or generally screw up. It might even work. @@ -81,6 +81,7 @@ * AX.25 032 Joerg(DL1BKE) Fixed DAMA timeout error. * ax25_send_frame() limits the number of enqueued * datagrams per socket. + * Jonathan(G4KLX) Remove auto-router. * * To do: * Restructure the ax25_rcv code to be cleaner/faster and @@ -124,7 +125,7 @@ * The null address is defined as a callsign of all spaces with an * SSID of zero. */ -ax25_address null_ax25_address = {{0x40,0x40,0x40,0x40,0x40,0x40,0x00}}; +ax25_address null_ax25_address = {{0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00}}; ax25_cb *volatile ax25_list = NULL; @@ -137,8 +138,7 @@ char c, *s; int n; - for (n = 0, s = buf; n < 6; n++) - { + for (n = 0, s = buf; n < 6; n++) { c = (a->ax25_call[n] >> 1) & 0x7F; if (c != ' ') *s++ = c; @@ -146,8 +146,7 @@ *s++ = '-'; - if ((n = ((a->ax25_call[6] >> 1) & 0x0F)) > 9) - { + if ((n = ((a->ax25_call[6] >> 1) & 0x0F)) > 9) { *s++ = '1'; n -= 10; } @@ -492,6 +491,7 @@ return a->uid; } return -ENOENT; + case SIOCAX25ADDUID: if(!suser()) return -EPERM; @@ -505,8 +505,8 @@ a->next = ax25_uid_list; ax25_uid_list = a; return 0; - case SIOCAX25DELUID: - { + + case SIOCAX25DELUID: { ax25_uid_assoc **l; if(!suser()) @@ -524,6 +524,9 @@ } return -ENOENT; } + + default: + return -EINVAL; } return -EINVAL; /*NOTREACHED */ @@ -673,7 +676,7 @@ init_timer(&ax25->timer); - ax25->dama_slave = 0; /* dl1bke 951121 */ + ax25->dama_slave = 0; ax25->rtt = (AX25_DEF_T1 * PR_SLOWHZ) / 2; ax25->t1 = AX25_DEF_T1 * PR_SLOWHZ; @@ -705,6 +708,7 @@ } else { ax25->window = AX25_DEF_WINDOW; } + ax25->device = NULL; ax25->digipeat = NULL; ax25->sk = NULL; @@ -789,7 +793,7 @@ } else { ax25_output(ax25, skb); } - ax25->idletimer = ax25->idle; /* dl1bke 960228 */ + ax25->idletimer = ax25->idle; return 1; /* It already existed */ } } @@ -809,10 +813,10 @@ } *ax25->digipeat = *digi; } else { - ax25_rt_build_path(ax25, dest); + ax25_rt_build_path(ax25, dest, dev); } - if (ax25_dev_is_dama_slave(ax25->device)) /* dl1bke 960116 */ + if (ax25_dev_is_dama_slave(ax25->device)) dama_establish_data_link(ax25); else ax25_establish_data_link(ax25); @@ -1208,7 +1212,6 @@ return NULL; } - /* dl1bke 960119: we have to copy the old digipeater list! */ *ax25->digipeat = *osk->ax25->digipeat; } @@ -1414,10 +1417,6 @@ } sk->ax25->digipeat->lastrepeat = 0; - } else { /* dl1bke 960117 */ - if (sk->debug) - printk("building digipeater path\n"); - ax25_rt_build_path(sk->ax25, &addr->sax25_call); } /* @@ -1548,7 +1547,6 @@ static int ax25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer) { - ax25_address *addr; struct full_sockaddr_ax25 *sax = (struct full_sockaddr_ax25 *)uaddr; struct sock *sk; unsigned char ndigi, i; @@ -1558,25 +1556,30 @@ if (peer != 0) { if (sk->state != TCP_ESTABLISHED) return -ENOTCONN; - addr = &sk->ax25->dest_addr; + + sax->fsa_ax25.sax25_family = AF_AX25; + sax->fsa_ax25.sax25_call = sk->ax25->dest_addr; + sax->fsa_ax25.sax25_ndigis = 0; + *uaddr_len = sizeof(struct full_sockaddr_ax25); + + if (sk->ax25->digipeat != NULL) { + ndigi = sk->ax25->digipeat->ndigi; + sax->fsa_ax25.sax25_ndigis = ndigi; + for (i = 0; i < ndigi; i++) + sax->fsa_digipeater[i] = sk->ax25->digipeat->calls[i]; + } } else { - addr = &sk->ax25->source_addr; + sax->fsa_ax25.sax25_family = AF_AX25; + sax->fsa_ax25.sax25_call = sk->ax25->source_addr; + sax->fsa_ax25.sax25_ndigis = 1; + *uaddr_len = sizeof(struct full_sockaddr_ax25); + + if (sk->ax25->device != NULL) + memcpy(&sax->fsa_digipeater[0], sk->ax25->device->dev_addr, AX25_ADDR_LEN); + else + sax->fsa_digipeater[0] = null_ax25_address; } - sax->fsa_ax25.sax25_family = AF_AX25; - sax->fsa_ax25.sax25_call = *addr; - sax->fsa_ax25.sax25_ndigis = 0; - *uaddr_len = sizeof(struct sockaddr_ax25); - - /* This will supply digipeat path on both getpeername() and getsockname() */ - if (sk->ax25->digipeat != NULL) { - ndigi = sk->ax25->digipeat->ndigi; - sax->fsa_ax25.sax25_ndigis = ndigi; - *uaddr_len += AX25_ADDR_LEN * ndigi; - for (i = 0; i < ndigi; i++) - sax->fsa_digipeater[i] = sk->ax25->digipeat->calls[i]; - } - return 0; } @@ -1615,13 +1618,6 @@ } /* - * Send the frame to the AX.25 auto-router - */ -#ifdef notdef /* dl1bke 960310 */ - ax25_rt_rx_frame(&src, dev, &dp); -#endif - - /* * Ours perhaps ? */ if (dp.lastrepeat + 1 < dp.ndigi) { /* Not yet digipeated completely */ @@ -1653,8 +1649,6 @@ return 0; } - ax25_rt_rx_frame(&src, dev, &dp); - build_ax25_addr(skb->data, &src, &dest, &dp, type, MODULUS); #ifdef CONFIG_FIREWALL if (call_fw_firewall(PF_AX25, skb->dev, skb->data, NULL) != FW_ACCEPT) { @@ -1702,14 +1696,11 @@ switch (skb->data[1]) { #ifdef CONFIG_INET case AX25_P_IP: - ax25_rt_rx_frame(&src, dev, &dp); skb_pull(skb,2); /* drop PID/CTRL */ - ax25_ip_mode_set(&src, dev, 'D'); ip_rcv(skb, dev, ptype); /* Note ptype here is the wrong one, fix me later */ break; case AX25_P_ARP: - ax25_rt_rx_frame(&src, dev, &dp); skb_pull(skb,2); arp_rcv(skb, dev, ptype); /* Note ptype here is wrong... */ break; @@ -1720,7 +1711,6 @@ if (sk->rmem_alloc >= sk->rcvbuf) { kfree_skb(skb, FREE_READ); } else { - ax25_rt_rx_frame(&src, dev, &dp); /* * Remove the control and PID. */ @@ -1764,7 +1754,6 @@ * free it immediately. This routine itself wakes the user context layers so we * do no further work */ - ax25_rt_rx_frame(&src, dev, &dp); if (ax25_process_rx_frame(ax25, skb, type, dama) == 0) kfree_skb(skb, FREE_READ); @@ -1790,7 +1779,6 @@ /* b) received SABM(E) */ if ((sk = ax25_find_listener(&dest, dev, SOCK_SEQPACKET)) != NULL) { - ax25_rt_rx_frame(&src, dev, &dp); if (sk->ack_backlog == sk->max_ack_backlog || (make = ax25_make_new(sk, dev)) == NULL) { if (mine) ax25_return_dm(dev, &src, &dest, &dp); @@ -1815,8 +1803,6 @@ return 0; } - ax25_rt_rx_frame(&src, dev, &dp); - if ((ax25 = ax25_create_cb()) == NULL) { ax25_return_dm(dev, &src, &dest, &dp); kfree_skb(skb, FREE_READ); @@ -1826,10 +1812,8 @@ ax25_fillin_cb(ax25, dev); ax25->idletimer = ax25->idle; #else - if (mine) { - ax25_rt_rx_frame(&src, dev, &dp); + if (mine) ax25_return_dm(dev, &src, &dest, &dp); - } kfree_skb(skb, FREE_READ); return 0; @@ -1882,7 +1866,7 @@ if (sk != NULL) { if (!sk->dead) - sk->data_ready(sk, skb->len ); + sk->data_ready(sk, skb->len); } else { kfree_skb(skb, FREE_READ); } @@ -1944,13 +1928,12 @@ ax25_digi *dp; ax25_digi dtmp; int lv; - int addr_len=msg->msg_namelen; + int addr_len = msg->msg_namelen; - if (sk->err) { + if (sk->err) return sock_error(sk); - } - if (flags|| msg->msg_control) + if (flags || msg->msg_control) return -EINVAL; if (sk->zapped) @@ -2079,9 +2062,8 @@ int er; int dama; - if (sk->err) { + if (sk->err) return sock_error(sk); - } if (addr_len != NULL) *addr_len = sizeof(*sax); @@ -2176,8 +2158,7 @@ put_fs_long(amount, (unsigned long *)arg); return 0; - case TIOCINQ: - { + case TIOCINQ: { struct sk_buff *skb; /* These two are safe on a single CPU system as only user tasks fiddle here */ if ((skb = skb_peek(&sk->receive_queue)) != NULL) @@ -2201,8 +2182,7 @@ case SIOCAX25ADDUID: /* Add a uid to the uid/call map table */ case SIOCAX25DELUID: /* Delete a uid from the uid/call map table */ - case SIOCAX25GETUID: - { + case SIOCAX25GETUID: { struct sockaddr_ax25 sax25; if ((err = verify_area(VERIFY_READ, (void *)arg, sizeof(struct sockaddr_ax25))) != 0) return err; @@ -2303,7 +2283,7 @@ ax25->window, ax25->paclen); - len += sprintf(buffer + len, " %s", ax25->dama_slave? " slave" : " no"); + len += sprintf(buffer + len, " %s", ax25->dama_slave ? " slave" : " no"); if (ax25->sk != NULL) { len += sprintf(buffer + len, " %5d %5d\n", @@ -2434,7 +2414,6 @@ * A small shim to dev_queue_xmit to handle the difference between * KISS AX.25 and BPQ AX.25. */ - void ax25_queue_xmit(struct sk_buff *skb, struct device *dev, int pri) { unsigned char *ptr; @@ -2449,8 +2428,8 @@ skb->protocol = htons (ETH_P_AX25); #ifdef CONFIG_BPQETHER - if(dev->type == ARPHRD_ETHER) { - static char bcast_addr[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; + if (dev->type == ARPHRD_ETHER) { + static char bcast_addr[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; int size; if(skb_headroom(skb) < AX25_BPQ_HEADER_LEN) { @@ -2546,8 +2525,7 @@ if (bp[16] == AX25_P_IP) { mode = ax25_ip_mode_get((ax25_address *)(bp + 1), dev); - if (mode == 'V' || mode == 'v' || (mode == ' ' && ax25_dev_get_value(dev, AX25_VALUES_IPDEFMODE) == 'V')) - { + if (mode == 'V' || (mode == ' ' && ax25_dev_get_value(dev, AX25_VALUES_IPDEFMODE) == 'V')) { /* * This is a workaround to try to keep the device locking * straight until skb->free=0 is abolished post 1.4. @@ -2593,7 +2571,6 @@ * dl1bke 960317: we use ax25_queue_xmit here to allow mode datagram * over ethernet. I don't know if this is valid, though. */ - ax25_dg_build_path(skb, (ax25_address *)(bp + 1), dev); ax25_queue_xmit(skb, dev, SOPRI_NORMAL); diff -ur --new-file old/linux/net/ax25/ax25_in.c new/linux/net/ax25/ax25_in.c --- old/linux/net/ax25/ax25_in.c Fri Apr 26 09:42:04 1996 +++ new/linux/net/ax25/ax25_in.c Wed Aug 7 07:41:57 1996 @@ -1,5 +1,5 @@ /* - * AX.25 release 031 + * AX.25 release 032 * * This is ALPHA test software. This code may break your machine, randomly fail to work with new * releases, misbehave and/or generally screw up. It might even work. @@ -32,6 +32,8 @@ * Joerg(DL1BKE) Renamed it to "IDLE" with a slightly * different behaviour. Fixed defrag * routine (I hope) + * AX.25 032 Jonathan(G4KLX) Remove auto-router. + * Darryl(G7LED) AX.25 segmentation fixed. */ #include @@ -70,66 +72,57 @@ static int ax25_rx_fragment(ax25_cb *ax25, struct sk_buff *skb) { struct sk_buff *skbn, *skbo; - int hdrlen; + int hdrlen, nhdrlen; if (ax25->fragno != 0) { if (!(*skb->data & SEG_FIRST)) { if ((ax25->fragno - 1) == (*skb->data & SEG_REM)) { - - /* enqueue fragment */ - + /* Enqueue fragment */ ax25->fragno = *skb->data & SEG_REM; skb_pull(skb, 1); /* skip fragno */ ax25->fraglen += skb->len; skb_queue_tail(&ax25->frag_queue, skb); - - /* last fragment received? */ + /* Last fragment received ? */ if (ax25->fragno == 0) { - if ((skbn = alloc_skb(AX25_MAX_HEADER_LEN + ax25->fraglen, GFP_ATOMIC)) == NULL) - return 0; + if ((skbn = alloc_skb(AX25_MAX_HEADER_LEN + ax25->fraglen, GFP_ATOMIC)) == NULL) { + while ((skbo = skb_dequeue(&ax25->frag_queue)) != NULL) + kfree_skb(skbo, FREE_READ); + return 1; + } skbn->free = 1; skbn->arp = 1; - skbn->dev = skb->dev; + skbn->dev = ax25->device; if (ax25->sk != NULL) { skbn->sk = ax25->sk; atomic_add(skbn->truesize, &ax25->sk->rmem_alloc); } - /* get first fragment from queue */ - - skbo = skb_dequeue(&ax25->frag_queue); - hdrlen = skbo->data - skbo->h.raw - 2; /* skip PID & fragno */ - - skb_push(skbo, hdrlen + 2); /* start of address field */ - skbn->data = skb_put(skbn, hdrlen); /* get space for info */ - memcpy(skbn->data, skbo->data, hdrlen); /* copy address field */ - skb_pull(skbo, hdrlen + 2); /* start of data */ - skb_pull(skbn, hdrlen + 1); /* ditto */ + skb_reserve(skbn, AX25_MAX_HEADER_LEN); - /* copy data from first fragment */ + /* Get first fragment from queue */ + skbo = skb_dequeue(&ax25->frag_queue); + hdrlen = skbo->data - skbo->h.raw; + nhdrlen = hdrlen - 2; - memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len); - kfree_skb(skbo, FREE_READ); - - /* add other fragment's data */ + skb_push(skbo, hdrlen); + skb_push(skbn, nhdrlen); + skbn->h.raw = skbn->data; + + /* Copy AX.25 headers */ + memcpy(skbn->data, skbo->data, nhdrlen); + skb_pull(skbn, nhdrlen); + skb_pull(skbo, hdrlen); - while ((skbo = skb_dequeue(&ax25->frag_queue)) != NULL) { + /* Copy data from the fragments */ + do { memcpy(skb_put(skbn, skbo->len), skbo->data, skbo->len); kfree_skb(skbo, FREE_READ); - } + } while ((skbo = skb_dequeue(&ax25->frag_queue)) != NULL); - ax25->fraglen = 0; /* reset counter */ - - /* - * mysteriously we need to re-adjust skb->data. - * Anyway, it seems to work. Do we have the address fields - * encoded TWICE in one sk_buff? - */ - - skb_pull(skbn, hdrlen); + ax25->fraglen = 0; if (ax25_rx_iframe(ax25, skbn) == 0) kfree_skb(skbn, FREE_READ); @@ -139,9 +132,10 @@ } } } else { - /* first fragment received? */ - + /* First fragment received */ if (*skb->data & SEG_FIRST) { + while ((skbo = skb_dequeue(&ax25->frag_queue)) != NULL) + kfree_skb(skbo, FREE_READ); ax25->fragno = *skb->data & SEG_REM; skb_pull(skb, 1); /* skip fragno */ ax25->fraglen = skb->len; @@ -181,7 +175,6 @@ case AX25_P_IP: skb_pull(skb, 1); /* Remove PID */ skb->h.raw = skb->data; - ax25_ip_mode_set(&ax25->dest_addr, ax25->device, 'V'); ip_rcv(skb, ax25->device, NULL); /* Wrong ptype */ queued = 1; break; @@ -273,7 +266,7 @@ break; default: - if (dama && pf) /* dl1bke 960116 */ + if (dama && pf) ax25_send_control(ax25, SABM, POLLON, C_COMMAND); break; } @@ -490,7 +483,7 @@ } if (ax25->condition & OWN_RX_BUSY_CONDITION) { if (pf) { - if (ax25->dama_slave) /* dl1bke 960114 */ + if (ax25->dama_slave) dama_enquiry_response(ax25); else ax25_enquiry_response(ax25); @@ -498,20 +491,21 @@ break; } if (ns == ax25->vr) { + ax25->vr = (ax25->vr + 1) % ax25->modulus; queued = ax25_rx_iframe(ax25, skb); if (ax25->condition & OWN_RX_BUSY_CONDITION) { + ax25->vr = ns; /* ax25->vr - 1 */ if (pf) { - if (ax25->dama_slave) /* dl1bke 960114 */ + if (ax25->dama_slave) dama_enquiry_response(ax25); else ax25_enquiry_response(ax25); } break; } - ax25->vr = (ax25->vr + 1) % ax25->modulus; ax25->condition &= ~REJECT_CONDITION; if (pf) { - if (ax25->dama_slave) /* dl1bke 960114 */ + if (ax25->dama_slave) dama_enquiry_response(ax25); else ax25_enquiry_response(ax25); @@ -524,14 +518,14 @@ } else { if (ax25->condition & REJECT_CONDITION) { if (pf) { - if (ax25->dama_slave) /* dl1bke 960114 */ + if (ax25->dama_slave) dama_enquiry_response(ax25); else ax25_enquiry_response(ax25); } } else { ax25->condition |= REJECT_CONDITION; - if (ax25->dama_slave) /* dl1bke 960114 */ + if (ax25->dama_slave) dama_enquiry_response(ax25); else ax25_send_control(ax25, REJ, pf, C_RESPONSE); @@ -660,7 +654,7 @@ case RR: ax25->condition &= ~PEER_RX_BUSY_CONDITION; - if ( pf && (type == C_RESPONSE || (ax25->dama_slave && type == C_COMMAND)) ) { + if (pf && (type == C_RESPONSE || (ax25->dama_slave && type == C_COMMAND))) { ax25->t1timer = 0; if (ax25_validate_nr(ax25, nr)) { ax25_frames_acked(ax25, nr); @@ -691,7 +685,7 @@ case REJ: ax25->condition &= ~PEER_RX_BUSY_CONDITION; - if ( pf && (type == C_RESPONSE || (ax25->dama_slave && type == C_COMMAND)) ) { + if (pf && (type == C_RESPONSE || (ax25->dama_slave && type == C_COMMAND))) { ax25->t1timer = 0; if (ax25_validate_nr(ax25, nr)) { ax25_frames_acked(ax25, nr); @@ -735,7 +729,7 @@ } ax25_frames_acked(ax25, nr); if (ax25->condition & OWN_RX_BUSY_CONDITION) { - if (pf) { /* dl1bke 960114 */ + if (pf) { if (ax25->dama_slave) ax25_enquiry_response(ax25); else @@ -744,9 +738,11 @@ break; } if (ns == ax25->vr) { + ax25->vr = (ax25->vr + 1) % ax25->modulus; queued = ax25_rx_iframe(ax25, skb); if (ax25->condition & OWN_RX_BUSY_CONDITION) { - if (pf) { /* dl1bke 960114 */ + ax25->vr = ns; /* ax25->vr - 1 */ + if (pf) { if (ax25->dama_slave) dama_enquiry_response(ax25); else @@ -754,10 +750,9 @@ } break; } - ax25->vr = (ax25->vr + 1) % ax25->modulus; ax25->condition &= ~REJECT_CONDITION; if (pf) { - if (ax25->dama_slave) /* dl1bke 960114 */ + if (ax25->dama_slave) dama_enquiry_response(ax25); else ax25_enquiry_response(ax25); @@ -769,7 +764,7 @@ } } else { if (ax25->condition & REJECT_CONDITION) { - if (pf) { /* dl1bke 960114 */ + if (pf) { if (ax25->dama_slave) dama_enquiry_response(ax25); else @@ -777,7 +772,7 @@ } } else { ax25->condition |= REJECT_CONDITION; - if (ax25->dama_slave) /* dl1bke 960114 */ + if (ax25->dama_slave) dama_enquiry_response(ax25); else ax25_send_control(ax25, REJ, pf, C_RESPONSE); diff -ur --new-file old/linux/net/ax25/ax25_out.c new/linux/net/ax25/ax25_out.c --- old/linux/net/ax25/ax25_out.c Mon May 13 11:15:23 1996 +++ new/linux/net/ax25/ax25_out.c Wed Aug 7 07:41:57 1996 @@ -1,5 +1,5 @@ /* - * AX.25 release 031 + * AX.25 release 032 * * This is ALPHA test software. This code may break your machine, randomly fail to work with new * releases, misbehave and/or generally screw up. It might even work. @@ -25,7 +25,6 @@ * AX.25 030 Jonathan(G4KLX) Added fragmentation to ax25_output. * Added support for extended AX.25. * AX.25 031 Joerg(DL1BKE) Added DAMA support - * * Joerg(DL1BKE) Modified fragmenter to fragment vanilla * AX.25 I-Frames. Added PACLEN parameter. * Joerg(DL1BKE) Fixed a problem with buffer allocation @@ -214,7 +213,7 @@ do { if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) { skb_queue_head(&ax25->write_queue, skb); - return; + break; } next = (ax25->vs + 1) % ax25->modulus; diff -ur --new-file old/linux/net/ax25/ax25_route.c new/linux/net/ax25/ax25_route.c --- old/linux/net/ax25/ax25_route.c Mon May 13 11:15:23 1996 +++ new/linux/net/ax25/ax25_route.c Wed Aug 7 07:41:57 1996 @@ -1,5 +1,5 @@ /* - * AX.25 release 031 + * AX.25 release 032 * * This is ALPHA test software. This code may break your machine, randomly fail to work with new * releases, misbehave and/or generally screw up. It might even work. @@ -37,6 +37,7 @@ * Joerg(DL1BKE) Fixed AX.25 routing of IP datagram and VC, new ioctl() * "SIOCAX25OPTRT" to set IP mode and a 'permanent' flag * on routes. + * AX.25 032 Jonathan(G4KLX) Remove auto-router. */ #include @@ -63,17 +64,12 @@ #include #include -#define AX25_ROUTE_MAX 128 - static struct ax25_route { struct ax25_route *next; ax25_address callsign; struct device *dev; ax25_digi *digipeat; - struct timeval stamp; - int n; char ip_mode; - char perm; } *ax25_route = NULL; static struct ax25_dev { @@ -82,120 +78,22 @@ unsigned short values[AX25_MAX_VALUES]; } *ax25_device = NULL; -static struct ax25_route * ax25_find_route(ax25_address *addr); +static struct ax25_route *ax25_find_route(ax25_address *, struct device *); /* * small macro to drop non-digipeated digipeaters and reverse path */ - static inline void ax25_route_invert(ax25_digi *in, ax25_digi *out) { int k; + for (k = 0; k < in->ndigi; k++) if (!in->repeated[k]) break; - in->ndigi = k; - ax25_digi_invert(in, out); - -} - -/* - * dl1bke 960310: new behaviour: - * - * * try to find an existing route to 'src', if found: - * - if the route was added manually don't adjust the timestamp - * - if this route is 'permanent' just do some statistics and return - * - overwrite device and digipeater path - * * no existing route found: - * - try to alloc a new entry - * - overwrite the oldest, not manually added entry if this fails. - * - * * updated on reception of frames directed to us _only_ - * - */ - -void ax25_rt_rx_frame(ax25_address *src, struct device *dev, ax25_digi *digi) -{ - unsigned long flags; - extern struct timeval xtime; - struct ax25_route *ax25_rt; - struct ax25_route *oldest; - int count; - - count = 0; - oldest = NULL; - for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) { - if (count == 0 || oldest->stamp.tv_sec == 0 || (ax25_rt->stamp.tv_sec != 0 && ax25_rt->stamp.tv_sec < oldest->stamp.tv_sec)) - oldest = ax25_rt; - - if (ax25cmp(&ax25_rt->callsign, src) == 0) { - if (ax25_rt->stamp.tv_sec != 0) - ax25_rt->stamp = xtime; - - if (ax25_rt->perm == AX25_RT_PERMANENT) { - ax25_rt->n++; - return; - } - - ax25_rt->dev = dev; - if (digi == NULL) { - /* drop old digipeater list */ - if (ax25_rt->digipeat != NULL) { - kfree_s(ax25_rt->digipeat, sizeof(ax25_digi)); - ax25_rt->digipeat = NULL; - } - return; - } - - if (ax25_rt->digipeat == NULL && (ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) - return; - - ax25_route_invert(digi, ax25_rt->digipeat); - return; - } - - count++; - } - - if (count > AX25_ROUTE_MAX) { - if (oldest->stamp.tv_sec == 0) - return; - if (oldest->digipeat != NULL) - kfree_s(oldest->digipeat, sizeof(ax25_digi)); - ax25_rt = oldest; - } else { - if ((ax25_rt = (struct ax25_route *)kmalloc(sizeof(struct ax25_route), GFP_ATOMIC)) == NULL) - return; /* No space */ - } - - ax25_rt->callsign = *src; - ax25_rt->dev = dev; - ax25_rt->digipeat = NULL; - ax25_rt->stamp = xtime; - ax25_rt->n = 1; - ax25_rt->ip_mode = ' '; - ax25_rt->perm = AX25_RT_DYNAMIC; - - if (digi != NULL) { - if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { - kfree_s(ax25_rt, sizeof(struct ax25_route)); - return; - } - - ax25_route_invert(digi, ax25_rt->digipeat); - /* used to be: *ax25_rt->digipeat = *digi; */ - } - - if (ax25_rt != oldest) { - save_flags(flags); - cli(); - - ax25_rt->next = ax25_route; - ax25_route = ax25_rt; + in->ndigi = k; - restore_flags(flags); - } + ax25_digi_invert(in, out); } void ax25_rt_device_down(struct device *dev) @@ -261,7 +159,6 @@ ax25_rt->digipeat->calls[i] = route.digi_addr[i]; } } - ax25_rt->stamp.tv_sec = 0; return 0; } } @@ -270,10 +167,7 @@ ax25_rt->callsign = route.dest_addr; ax25_rt->dev = dev; ax25_rt->digipeat = NULL; - ax25_rt->stamp.tv_sec = 0; - ax25_rt->n = 0; ax25_rt->ip_mode = ' '; - ax25_rt->perm = AX25_RT_DYNAMIC; if (route.digi_count != 0) { if ((ax25_rt->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) { kfree_s(ax25_rt, sizeof(struct ax25_route)); @@ -323,40 +217,36 @@ } } break; + case SIOCAX25OPTRT: if ((err = verify_area(VERIFY_READ, arg, sizeof(rt_option))) != 0) return err; memcpy_fromfs(&rt_option, arg, sizeof(rt_option)); if ((dev = ax25rtr_get_dev(&rt_option.port_addr)) == NULL) return -EINVAL; - ax25_rt = ax25_route; - while (ax25_rt != NULL) { + for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) { if (ax25_rt->dev == dev && ax25cmp(&rt_option.dest_addr, &ax25_rt->callsign) == 0) { - switch(rt_option.cmd) { - case AX25_SET_RT_PERMANENT: - ax25_rt->perm = (char) rt_option.arg; - ax25_rt->stamp.tv_sec = 0; - break; + switch (rt_option.cmd) { case AX25_SET_RT_IPMODE: switch (rt_option.arg) { - case AX25_RT_IPMODE_DEFAULT: - ax25_rt->ip_mode = ' '; - break; - case AX25_RT_IPMODE_DATAGRAM: - ax25_rt->ip_mode = 'D'; - break; - case AX25_RT_IPMODE_VC: - ax25_rt->ip_mode = 'V'; + case ' ': + case 'D': + case 'V': + ax25_rt->ip_mode = rt_option.arg; break; default: return -EINVAL; } break; + default: + return -EINVAL; } } - ax25_rt = ax25_rt->next; } break; + + default: + return -EINVAL; } return 0; @@ -373,26 +263,22 @@ cli(); - len += sprintf(buffer, "callsign dev count time mode F digipeaters\n"); + len += sprintf(buffer, "callsign dev mode digipeaters\n"); for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) { if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0) callsign = "default"; else callsign = ax2asc(&ax25_rt->callsign); - len += sprintf(buffer + len, "%-9s %-4s %5d %9d", + len += sprintf(buffer + len, "%-9s %-4s", callsign, - ax25_rt->dev ? ax25_rt->dev->name : "???", - ax25_rt->n, - ax25_rt->stamp.tv_sec); + ax25_rt->dev ? ax25_rt->dev->name : "???"); switch (ax25_rt->ip_mode) { case 'V': - case 'v': len += sprintf(buffer + len, " vc"); break; case 'D': - case 'd': len += sprintf(buffer + len, " dg"); break; default: @@ -400,20 +286,6 @@ break; } - switch (ax25_rt->perm) { - case AX25_RT_DYNAMIC: - if (ax25_rt->stamp.tv_sec == 0) - len += sprintf(buffer + len, " M"); - else - len += sprintf(buffer + len, " "); - break; - case AX25_RT_PERMANENT: - len += sprintf(buffer + len, " P"); - break; - default: - len += sprintf(buffer + len, " ?"); - } - if (ax25_rt->digipeat != NULL) for (i = 0; i < ax25_rt->digipeat->ndigi; i++) len += sprintf(buffer + len, " %s", ax2asc(&ax25_rt->digipeat->calls[i])); @@ -479,8 +351,7 @@ /* * Find AX.25 route */ - -static struct ax25_route * ax25_find_route(ax25_address *addr) +static struct ax25_route *ax25_find_route(ax25_address *addr, struct device *dev) { struct ax25_route *ax25_spe_rt = NULL; struct ax25_route *ax25_def_rt = NULL; @@ -491,10 +362,17 @@ * route if none is found; */ for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) { - if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev != NULL) - ax25_spe_rt = ax25_rt; - if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev != NULL) - ax25_def_rt = ax25_rt; + if (dev == NULL) { + if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev != NULL) + ax25_spe_rt = ax25_rt; + if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev != NULL) + ax25_def_rt = ax25_rt; + } else { + if (ax25cmp(&ax25_rt->callsign, addr) == 0 && ax25_rt->dev == dev) + ax25_spe_rt = ax25_rt; + if (ax25cmp(&ax25_rt->callsign, &null_ax25_address) == 0 && ax25_rt->dev == dev) + ax25_def_rt = ax25_rt; + } } if (ax25_spe_rt != NULL) @@ -508,7 +386,6 @@ * a target on the digipeater path but w/o having a special route * set before, the path has to be truncated from your target on. */ - static inline void ax25_adjust_path(ax25_address *addr, ax25_digi *digipeat) { int k; @@ -530,14 +407,14 @@ struct ax25_route *ax25_rt; ax25_address *call; - if ((ax25_rt = ax25_find_route(addr)) == NULL) + if ((ax25_rt = ax25_find_route(addr, NULL)) == NULL) return -EHOSTUNREACH; + ax25->device = ax25_rt->dev; + if ((call = ax25_findbyuid(current->euid)) == NULL) { if (ax25_uid_policy && !suser()) return -EPERM; - if (ax25->device == NULL) - return -ENODEV; call = (ax25_address *)ax25->device->dev_addr; } @@ -560,19 +437,20 @@ * dl1bke 960117: build digipeater path * dl1bke 960301: use the default route if it exists */ -void ax25_rt_build_path(ax25_cb *ax25, ax25_address *addr) +void ax25_rt_build_path(ax25_cb *ax25, ax25_address *addr, struct device *dev) { struct ax25_route *ax25_rt; - ax25_rt = ax25_find_route(addr); + if ((ax25_rt = ax25_find_route(addr, dev)) == NULL) + return; - if (ax25_rt == NULL || ax25_rt->digipeat == NULL) + if (ax25_rt->digipeat == NULL) return; if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) return; - ax25->device = ax25_rt->dev; + ax25->device = ax25_rt->dev; *ax25->digipeat = *ax25_rt->digipeat; ax25_adjust_path(addr, ax25->digipeat); } @@ -587,8 +465,10 @@ skb_pull(skb, 1); /* skip KISS command */ - ax25_rt = ax25_find_route(addr); - if (ax25_rt == NULL || ax25_rt->digipeat == NULL) + if ((ax25_rt = ax25_find_route(addr, dev)) == NULL) + return; + + if (ax25_rt->digipeat == NULL) return; digipeat = *ax25_rt->digipeat; @@ -611,22 +491,6 @@ } /* - * Register the mode of an incoming IP frame. It is assumed that an entry - * already exists in the routing table. - */ -void ax25_ip_mode_set(ax25_address *callsign, struct device *dev, char ip_mode) -{ - struct ax25_route *ax25_rt; - - for (ax25_rt = ax25_route; ax25_rt != NULL; ax25_rt = ax25_rt->next) { - if (ax25cmp(&ax25_rt->callsign, callsign) == 0 && ax25_rt->dev == dev) { - ax25_rt->ip_mode = ip_mode; - return; - } - } -} - -/* * Return the IP mode of a given callsign/device pair. */ char ax25_ip_mode_get(ax25_address *callsign, struct device *dev) @@ -908,6 +772,9 @@ ax25_bpqdev = bpqdev; restore_flags(flags); break; + + default: + return -EINVAL; } return 0; diff -ur --new-file old/linux/net/ax25/ax25_subr.c new/linux/net/ax25/ax25_subr.c --- old/linux/net/ax25/ax25_subr.c Mon May 6 11:26:17 1996 +++ new/linux/net/ax25/ax25_subr.c Wed Aug 7 07:41:57 1996 @@ -1,5 +1,5 @@ /* - * AX.25 release 031 + * AX.25 release 032 * * This is ALPHA test software. This code may break your machine, randomly fail to work with new * releases, misbehave and/or generally screw up. It might even work. @@ -101,7 +101,7 @@ skb->free = 1; kfree_skb(skb, FREE_WRITE); ax25->va = (ax25->va + 1) % ax25->modulus; - if (ax25->dama_slave) /* dl1bke 960120 */ + if (ax25->dama_slave) ax25->n2count = 0; } } diff -ur --new-file old/linux/net/ax25/ax25_timer.c new/linux/net/ax25/ax25_timer.c --- old/linux/net/ax25/ax25_timer.c Fri Apr 26 09:42:04 1996 +++ new/linux/net/ax25/ax25_timer.c Wed Aug 7 07:41:57 1996 @@ -1,5 +1,5 @@ /* - * AX.25 release 031 + * AX.25 release 032 * * This is ALPHA test software. This code may break your machine, randomly fail to work with new * releases, misbehave and/or generally screw up. It might even work. @@ -113,7 +113,7 @@ if (ax25->sk != NULL) { if (ax25->sk->rmem_alloc < (ax25->sk->rcvbuf / 2) && (ax25->condition & OWN_RX_BUSY_CONDITION)) { ax25->condition &= ~OWN_RX_BUSY_CONDITION; - if (!ax25->dama_slave) /* dl1bke */ + if (!ax25->dama_slave) ax25_send_control(ax25, RR, POLLOFF, C_RESPONSE); ax25->condition &= ~ACK_PENDING_CONDITION; break; @@ -123,7 +123,7 @@ * Check for frames to transmit. */ if (!ax25->dama_slave) - ax25_kick(ax25); /* dl1bke 960114 */ + ax25_kick(ax25); break; default: @@ -134,7 +134,7 @@ if (ax25->state == AX25_STATE_3 || ax25->state == AX25_STATE_4) { if (ax25->condition & ACK_PENDING_CONDITION) { ax25->condition &= ~ACK_PENDING_CONDITION; - if (!ax25->dama_slave) /* dl1bke 960114 */ + if (!ax25->dama_slave) ax25_timeout_response(ax25); } } @@ -272,7 +272,7 @@ #endif ax25_clear_queues(ax25); ax25->state = AX25_STATE_0; - ax25_send_control(ax25, DISC, POLLON, C_COMMAND); /* dl1bke */ + ax25_send_control(ax25, DISC, POLLON, C_COMMAND); if (ax25->sk != NULL) { ax25->sk->state = TCP_CLOSE; @@ -283,14 +283,14 @@ } } else { ax25->n2count++; - if (!ax25_dev_is_dama_slave(ax25->device)) /* dl1bke */ + if (!ax25_dev_is_dama_slave(ax25->device)) ax25_send_control(ax25, DISC, POLLON, C_COMMAND); } break; case AX25_STATE_3: ax25->n2count = 1; - if (!ax25->dama_slave) /* dl1bke 960114 */ + if (!ax25->dama_slave) ax25_transmit_enquiry(ax25); ax25->state = AX25_STATE_4; break; @@ -314,7 +314,7 @@ } } else { ax25->n2count++; - if (!ax25->dama_slave) /* dl1bke 960114 */ + if (!ax25->dama_slave) ax25_transmit_enquiry(ax25); } break; diff -ur --new-file old/linux/net/bridge/br.c new/linux/net/bridge/br.c --- old/linux/net/bridge/br.c Mon May 13 11:15:24 1996 +++ new/linux/net/bridge/br.c Fri Jul 19 07:24:05 1996 @@ -1052,6 +1052,7 @@ int br_receive_frame(struct sk_buff *skb) /* 3.5 */ { int port; + int i; if (br_stats.flags & BR_DEBUG) printk("br_receive_frame: "); @@ -1130,6 +1131,8 @@ port_info[port].dev->dev_addr, ETH_ALEN) == 0) { + /* Packet is for us */ + skb->pkt_type = PACKET_HOST; return(0); /* pass frame up our stack (this will */ /* happen in net_bh() in dev.c) */ } @@ -1159,6 +1162,13 @@ printk(KERN_CRIT "br_tx_frame: no skb!\n"); return(0); } + + if (!skb->dev) + { + printk(KERN_CRIT "br_tx_frame: no dev!\n"); + return(0); + } + /* check for loopback */ if (skb->dev->flags & IFF_LOOPBACK) return(0); @@ -1289,7 +1299,7 @@ /* * Send flood and drop. */ - if (!f | !(f->flags & FDB_ENT_VALID)) { + if (!f || !(f->flags & FDB_ENT_VALID)) { /* not found; flood all ports */ br_flood(skb, port); return(br_dev_drop(skb)); @@ -1297,7 +1307,7 @@ /* * Sending */ - if (port_info[f->port].state == Forwarding) { + if (f->port!=port && port_info[f->port].state == Forwarding) { /* has entry expired? */ if (f->timer + fdb_aging_time < CURRENT_TIME) { /* timer expired, invalidate entry */ @@ -1354,9 +1364,15 @@ if (port_info[i].state == Forwarding) { nskb = skb_clone(skb, GFP_ATOMIC); + if(nskb==NULL) + continue; /* mark that's we've been here... */ nskb->pkt_bridged = IS_BRIDGED; - nskb->arp = skb->arp; + /* Send to each port in turn */ + nskb->dev= port_info[i].dev; + /* To get here we must have done ARP already, + or have a received valid MAC header */ + nskb->arp = 1; /* printk("Flood to port %d\n",i);*/ nskb->h.raw = nskb->data + ETH_HLEN; diff -ur --new-file old/linux/net/core/dev.c new/linux/net/core/dev.c --- old/linux/net/core/dev.c Thu Jun 6 20:22:24 1996 +++ new/linux/net/core/dev.c Thu Aug 1 14:43:04 1996 @@ -617,7 +617,10 @@ cli(); skb_push(skb,offset); /* Put header back on for bridge */ if(br_receive_frame(skb)) + { + sti(); continue; + } /* * Pull the MAC header off for the copy going to * the upper layers. diff -ur --new-file old/linux/net/core/sock.c new/linux/net/core/sock.c --- old/linux/net/core/sock.c Fri Jun 7 10:58:11 1996 +++ new/linux/net/core/sock.c Sat Aug 17 19:28:10 1996 @@ -70,6 +70,7 @@ * Alan Cox : Allow NULL arguments on some SO_ opts * Alan Cox : Generic socket allocation to make hooks * easier (suggested by Craig Metz). + * Michael Pall : SO_ERROR returns positive errno again * * To Fix: * @@ -185,6 +186,8 @@ val = SK_RMEM_MAX*2; if(val < 256) val = 256; + if(val > 65535) + val = 65535; sk->rcvbuf = val; return(0); @@ -278,7 +281,7 @@ break; case SO_ERROR: - val = sock_error(sk); + val = -sock_error(sk); if(val==0) val=xchg(&sk->err_soft,0); break; @@ -346,7 +349,7 @@ struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, int priority) { if (sk) { - if (force || sk->wmem_alloc + size < sk->sndbuf) { + if (force || sk->wmem_alloc < sk->sndbuf) { struct sk_buff * skb = alloc_skb(size, priority); if (skb) atomic_add(skb->truesize, &sk->wmem_alloc); @@ -360,7 +363,7 @@ struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force, int priority) { if (sk) { - if (force || sk->rmem_alloc + size < sk->rcvbuf) { + if (force || sk->rmem_alloc < sk->rcvbuf) { struct sk_buff *skb = alloc_skb(size, priority); if (skb) atomic_add(skb->truesize, &sk->rmem_alloc); diff -ur --new-file old/linux/net/ethernet/eth.c new/linux/net/ethernet/eth.c --- old/linux/net/ethernet/eth.c Mon May 13 11:15:24 1996 +++ new/linux/net/ethernet/eth.c Sat Aug 3 10:46:51 1996 @@ -273,7 +273,7 @@ int ip_length; IS_SKB(dest); - eth=(struct ethhdr *)dest->data; + eth=(struct ethhdr *)src; if(eth->h_proto!=htons(ETH_P_IP)) { memcpy(dest->data,src,length); diff -ur --new-file old/linux/net/ipv4/Config.in new/linux/net/ipv4/Config.in --- old/linux/net/ipv4/Config.in Thu Jun 6 11:58:21 1996 +++ new/linux/net/ipv4/Config.in Fri Jul 19 07:24:05 1996 @@ -7,7 +7,7 @@ bool 'IP: firewalling' CONFIG_IP_FIREWALL if [ "$CONFIG_IP_FIREWALL" = "y" ]; then bool 'IP: firewall packet logging' CONFIG_IP_FIREWALL_VERBOSE - if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_IP_FORWARD" = "y" ]; then bool 'IP: masquerading (EXPERIMENTAL)' CONFIG_IP_MASQUERADE if [ "$CONFIG_IP_MASQUERADE" != "n" ]; then comment 'Protocol-specific masquerading support will be built as modules.' diff -ur --new-file old/linux/net/ipv4/af_inet.c new/linux/net/ipv4/af_inet.c --- old/linux/net/ipv4/af_inet.c Thu Aug 29 16:32:45 1996 +++ new/linux/net/ipv4/af_inet.c Thu Aug 29 16:33:31 1996 @@ -105,7 +105,7 @@ #include #endif -#ifdef CONFIG_ATM_TCP +#if defined(CONFIG_ATM_TCP) || defined(CONFIG_ATM_TCP_MODULE) #include int (*atmtcp_attach_hook)(struct socket *sock) = NULL; #endif @@ -708,7 +708,6 @@ sk->timer.function = &net_timer; skb_queue_head_init(&sk->back_log); sock->data =(void *) sk; - sk->dummy_th.doff = sizeof(sk->dummy_th)/4; sk->ip_ttl=ip_statistics.IpDefaultTTL; if(sk->type==SOCK_RAW && protocol==IPPROTO_RAW) sk->ip_hdrincl=1; @@ -831,7 +830,7 @@ /* check this error. */ if (sk->state != TCP_CLOSE) - return(-EIO); + return(-EINVAL); if(addr_lenreuse || sk2->state==TCP_LISTEN) + if (!sk2->reuse || sk2->state==TCP_LISTEN) { sti(); return(-EADDRINUSE); @@ -1122,6 +1121,12 @@ newsock->data = NULL; return err; } + if (sk2->state == TCP_CLOSE) + { + destroy_sock(sk2); + newsock->data=NULL; + return -ECONNABORTED; + } newsock->state = SS_CONNECTED; return(0); } @@ -1350,7 +1355,7 @@ return((*dlci_ioctl_hook)(cmd, (void *) arg)); #endif return -ENOPKG; -#ifdef CONFIG_ATM_TCP +#if defined(CONFIG_ATM_TCP) || defined(CONFIG_ATM_TCP_MODULE) case SIOCSIFATMTCP: if (atmtcp_attach_hook) return atmtcp_attach_hook(sock); diff -ur --new-file old/linux/net/ipv4/arp.c new/linux/net/ipv4/arp.c --- old/linux/net/ipv4/arp.c Thu Aug 29 16:32:46 1996 +++ new/linux/net/ipv4/arp.c Thu Aug 29 16:33:32 1996 @@ -58,6 +58,8 @@ * Jonathan Layes : Added arpd support through kerneld * message queue (960314) * Mike Shaver : /proc/sys/net/ipv4/arp_* support + * Stuart Cheshire : Metricom and grat arp fixes + * *** FOR 2.1 clean this up *** */ /* RFC1122 Status: @@ -1136,6 +1138,7 @@ else dev_queue_xmit(skb,skb->dev,skb->sk->priority); } + cli(); } restore_flags(flags); } @@ -1931,18 +1934,10 @@ else arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha); -/* - * Handle gratuitous arp. - */ - arp_fast_lock(); - arp_update(sip, sha, dev, 0, NULL, 1); - arp_unlock(); - kfree_skb(skb, FREE_READ); - return 0; } arp_fast_lock(); - arp_update(sip, sha, dev, 0, NULL, ip_chk_addr(tip) != IS_MYADDR); + arp_update(sip, sha, dev, 0, NULL, ip_chk_addr(tip) != IS_MYADDR && dev->type != ARPHRD_METRICOM); arp_unlock(); kfree_skb(skb, FREE_READ); return 0; @@ -1994,7 +1989,7 @@ } else { - if (ip_chk_addr(ip)) + if (ip_chk_addr(ip) && dev->type != ARPHRD_METRICOM) return -EINVAL; if (!dev) { diff -ur --new-file old/linux/net/ipv4/igmp.c new/linux/net/ipv4/igmp.c --- old/linux/net/ipv4/igmp.c Mon May 13 11:15:24 1996 +++ new/linux/net/ipv4/igmp.c Sat Aug 17 19:28:10 1996 @@ -1,7 +1,7 @@ /* - * Linux NET3: Internet Gateway Management Protocol [IGMP] + * Linux NET3: Internet Group Management Protocol [IGMP] * - * This code implements the IGMP protocol as defined in RFC1122. There has + * This code implements the IGMP protocol as defined in RFC1112. There has * been a further revision of this protocol since which is now supported. * * If you have trouble with this module be careful what gcc you have used, @@ -56,6 +56,11 @@ * Christian Daudt : igmp_heard_report now only calls * igmp_timer_expire if tm->running is * true (960216). + * Malcolm Beattie : ttl comparison wrong in igmp_rcv made + * igmp_heard_query never trigger. Expiry + * miscalculation fixed in igmp_heard_query + * and random() made to return unsigned to + * prevent negative expiry times. */ @@ -207,7 +212,7 @@ } } -extern __inline__ int random(void) +extern __inline__ unsigned int random(void) { static unsigned long seed=152L; seed=seed*69069L+1; @@ -326,7 +331,7 @@ { if(im->tm_running) { - if(im->timer.expires>max_resp_time*HZ/IGMP_TIMER_SCALE) + if(im->timer.expires>jiffies+max_resp_time*HZ/IGMP_TIMER_SCALE) { igmp_stop_timer(im); igmp_start_timer(im,max_resp_time); @@ -447,7 +452,7 @@ } ih=(struct igmphdr *)skb->h.raw; - if(skb->len ip_hdr->ttl>1 || ip_compute_csum((void *)skb->h.raw,sizeof(struct igmphdr))) + if(skb->len ip_hdr->ttl<1 || ip_compute_csum((void *)skb->h.raw,sizeof(struct igmphdr))) { kfree_skb(skb, FREE_READ); return 0; diff -ur --new-file old/linux/net/ipv4/ip_forward.c new/linux/net/ipv4/ip_forward.c --- old/linux/net/ipv4/ip_forward.c Thu Jun 6 20:22:24 1996 +++ new/linux/net/ipv4/ip_forward.c Wed Aug 7 12:59:29 1996 @@ -39,7 +39,7 @@ #include #include #include - + #ifdef CONFIG_IP_FORWARD #ifdef CONFIG_IP_MROUTE @@ -57,8 +57,11 @@ * Firstly push down and install the IPIP header. */ struct iphdr *iph=(struct iphdr *)skb_push(skb,sizeof(struct iphdr)); + if(len>65515) len=65515; + + iph->version = 4; iph->tos = skb->ip_hdr->tos; iph->ttl = skb->ip_hdr->ttl; @@ -67,17 +70,26 @@ iph->saddr = out->pa_addr; iph->protocol = IPPROTO_IPIP; iph->ihl = 5; - iph->tot_len = htons(skb->len); + iph->tot_len = htons(skb->len + len); /* Anand, ernet */ iph->id = htons(ip_id_count++); ip_send_check(iph); skb->dev = out; skb->arp = 1; - skb->raddr=daddr; + skb->raddr=daddr; /* Router address is not destination address. The + * correct value is given eventually. I have not + * removed this statement. But could have. + * Anand, ernet. + */ /* * Now add the physical header (driver will push it down). */ - if (out->hard_header && out->hard_header(skb, out, ETH_P_IP, NULL, NULL, len)<0) + + /* The last parameter of out->hard_header() needed skb->len + len. + * Anand, ernet. + */ + if (out->hard_header && out->hard_header(skb, out, ETH_P_IP, NULL, NULL, + skb->len + len)<0) skb->arp=0; /* * Read to queue for transmission. @@ -121,18 +133,22 @@ */ iph = skb->h.iph; - iph->ttl--; + if (!(is_frag&IPFWD_NOTTLDEC)) + { + unsigned long checksum = iph->check; + iph->ttl--; /* * Re-compute the IP header checksum. - * This is inefficient. We know what has happened to the header - * and could thus adjust the checksum as Phil Karn does in KA9Q + * This is efficient. We know what has happened to the header + * and can thus adjust the checksum as Phil Karn does in KA9Q + * except we do this in "network byte order". */ - - iph->check = ntohs(iph->check) + 0x0100; - if ((iph->check & 0xFF00) == 0) - iph->check++; /* carry overflow */ - iph->check = htons(iph->check); + checksum += htons(0x0100); + /* carry overflow? */ + checksum += checksum >> 16; + iph->check = checksum; + } if (iph->ttl <= 0) { @@ -141,8 +157,14 @@ return -1; } + /* If IPFWD_MULTITUNNEL flag is set, then we have to perform routing + * decision so as to reach the other end of the tunnel. This condition + * also means that we are dealing with a unicast IP packet "in a way". + * Anand, ernet. + */ + #ifdef CONFIG_IP_MROUTE - if(!(is_frag&IPFWD_MULTICASTING)) + if(!(is_frag&IPFWD_MULTICASTING) || (is_frag&IPFWD_MULTITUNNEL)) { #endif /* @@ -205,6 +227,12 @@ icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, raddr, dev); #endif #ifdef CONFIG_IP_MROUTE + + /* This is for ip encap. Anand, ernet.*/ + + if (is_frag&IPFWD_MULTITUNNEL) { + encap=20; + } } else { @@ -287,7 +315,7 @@ #endif IS_SKB(skb); - if (skb->len+encap > dev2->mtu && (ntohs(iph->frag_off) & IP_DF)) + if (skb->len+encap > dev2->mtu && (iph->frag_off & htons(IP_DF))) { ip_statistics.IpFragFails++; icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(dev2->mtu), dev); @@ -326,8 +354,21 @@ #ifdef CONFIG_IP_MROUTE if(is_frag&IPFWD_MULTITUNNEL) { - skb_reserve(skb,(encap+dev->hard_header_len+15)&~15); /* 16 byte aligned IP headers are good */ - ip_encap(skb2,skb->len, dev2, raddr); + skb_reserve(skb2,(encap+dev2->hard_header_len+15)&~15); /* 16 byte aligned IP headers are good */ + +/* We need to pass on IP information of the incoming packet to ip_encap() + * to fillin ttl, and tos fields.The destination should be target_addr. + * Anand, ernet. + */ + + skb2->ip_hdr = skb->ip_hdr; + + ip_encap(skb2,skb->len, dev2, target_addr); + +/* The router address is got earlier that to take us to the remote tunnel + * Anand, ernet. + */ + skb2->raddr = rt->rt_gateway; } else #endif @@ -341,7 +382,6 @@ ptr = skb_put(skb2,skb->len); skb2->free = 1; skb2->h.raw = ptr; - /* * Copy the packet data into the new buffer. */ @@ -517,3 +557,6 @@ #endif + + + diff -ur --new-file old/linux/net/ipv4/ip_fragment.c new/linux/net/ipv4/ip_fragment.c --- old/linux/net/ipv4/ip_fragment.c Mon May 13 11:15:24 1996 +++ new/linux/net/ipv4/ip_fragment.c Wed Aug 7 13:00:08 1996 @@ -610,6 +610,8 @@ struct sk_buff *skb2; int left, mtu, hlen, len; int offset; + + unsigned short true_hard_header_len; /* * Point into the IP datagram header. @@ -624,12 +626,18 @@ #endif /* + * Calculate the length of the link-layer header appended to + * the IP-packet. + */ + true_hard_header_len = ((unsigned char *)iph) - raw; + + /* * Setup starting values. */ hlen = iph->ihl * 4; left = ntohs(iph->tot_len) - hlen; /* Space per frame */ - hlen += dev->hard_header_len; /* Total header size */ + hlen += true_hard_header_len; mtu = (dev->mtu - hlen); /* Size of data space */ ptr = (raw + hlen); /* Where to start from */ @@ -637,7 +645,7 @@ * Check for any "DF" flag. [DF means do not fragment] */ - if (ntohs(iph->frag_off) & IP_DF) + if (iph->frag_off & htons(IP_DF)) { ip_statistics.IpFragFails++; NETDEBUG(printk("ip_queue_xmit: frag needed\n")); @@ -706,8 +714,11 @@ */ skb2->arp = skb->arp; + skb2->protocol = htons(ETH_P_IP); /* Atleast PPP needs this */ +#if 0 if(skb->free==0) printk(KERN_ERR "IP fragmenter: BUG free!=1 in fragmenter\n"); +#endif skb2->free = 1; skb_put(skb2,len + hlen); skb2->h.raw=(char *) skb2->data; @@ -735,7 +746,7 @@ memcpy(skb2->h.raw + hlen, ptr, len); left -= len; - skb2->h.raw+=dev->hard_header_len; + skb2->h.raw+=true_hard_header_len; /* * Fill in the new header fields. diff -ur --new-file old/linux/net/ipv4/ip_fw.c new/linux/net/ipv4/ip_fw.c --- old/linux/net/ipv4/ip_fw.c Sun Jun 9 08:22:34 1996 +++ new/linux/net/ipv4/ip_fw.c Sat Jun 29 11:00:48 1996 @@ -264,9 +264,11 @@ /* * Too short. + * + * But only too short for a packet with ports... */ - else if(ntohs(ip->tot_len)<8+(ip->ihl<<2)) + else if((ntohs(ip->tot_len)<8+(ip->ihl<<2))&&(ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP)) return FW_BLOCK; src = ip->saddr; diff -ur --new-file old/linux/net/ipv4/ip_masq_app.c new/linux/net/ipv4/ip_masq_app.c --- old/linux/net/ipv4/ip_masq_app.c Fri May 31 12:46:27 1996 +++ new/linux/net/ipv4/ip_masq_app.c Fri Jun 28 17:49:55 1996 @@ -2,7 +2,7 @@ * IP_MASQ_APP application masquerading module * * - * Version: @(#)ip_masq_app.c 0.03 03/96 + * Version: @(#)ip_masq_app.c 0.04 96/06/17 * * Author: Juan Jose Ciarlante, * @@ -13,7 +13,8 @@ * 2 of the License, or (at your option) any later version. * * Fixes: - * JJC : Implemented also input pkt hook + * JJC : Implemented also input pkt hook + * Miquel van Smoorenburg : Copy more stuff when resizing skb * * * FIXME: @@ -502,6 +503,7 @@ { int maxsize, diff, o_offset; struct sk_buff *n_skb; + int offset; maxsize = skb->truesize - sizeof(struct sk_buff); @@ -521,7 +523,9 @@ skb->end = skb->head+n_len; } else { /* - * Sizes differ, make a copy + * Sizes differ, make a copy. + * + * FIXME: move this to core/sbuff.c:skb_grow() */ n_skb = alloc_skb(MAX_HEADER + skb->len + diff, pri); @@ -534,8 +538,22 @@ n_skb->free = skb->free; skb_reserve(n_skb, MAX_HEADER); skb_put(n_skb, skb->len + diff); - n_skb->h.raw = n_skb->data + (skb->h.raw - skb->data); - + + /* + * Copy as much data from the old skb as possible. Even + * though we're only forwarding packets, we need stuff + * like skb->protocol (PPP driver wants it). + */ + offset = n_skb->data - skb->data; + n_skb->h.raw = skb->h.raw + offset; + n_skb->when = skb->when; + n_skb->dev = skb->dev; + n_skb->mac.raw = skb->mac.raw + offset; + n_skb->ip_hdr = (struct iphdr *)(((char *)skb->ip_hdr)+offset); + n_skb->pkt_type = skb->pkt_type; + n_skb->protocol = skb->protocol; + n_skb->ip_summed = skb->ip_summed; + /* * Copy pkt in new buffer */ diff -ur --new-file old/linux/net/ipv4/ip_output.c new/linux/net/ipv4/ip_output.c --- old/linux/net/ipv4/ip_output.c Thu Jun 6 20:22:24 1996 +++ new/linux/net/ipv4/ip_output.c Tue Jul 9 13:28:32 1996 @@ -107,7 +107,7 @@ /* Recurse. The device check against IFF_LOOPBACK will stop infinite recursion */ /*printk("Loopback output queued [%lX to %lX].\n", newskb->ip_hdr->saddr,newskb->ip_hdr->daddr);*/ - ip_queue_xmit(NULL, dev, newskb, 1); + ip_queue_xmit(NULL, dev, newskb, 2); } @@ -160,9 +160,9 @@ skb->dev = dev; skb->arp = 1; skb->protocol = htons(ETH_P_IP); + skb_reserve(skb,MAX_HEADER); if (dev->hard_header) { - skb_reserve(skb,MAX_HEADER); if (rt && dev == rt->rt_dev && rt->rt_hh) { memcpy(skb_push(skb,dev->hard_header_len),rt->rt_hh->hh_data,dev->hard_header_len); @@ -574,7 +574,7 @@ ip_statistics.IpOutRequests++; #ifdef CONFIG_IP_MULTICAST - if(sk && MULTICAST(daddr) && *sk->ip_mc_name) + if(MULTICAST(daddr) && *sk->ip_mc_name) { dev=dev_get(sk->ip_mc_name); if(!dev) @@ -710,8 +710,10 @@ } return 0; } - length -= sizeof(struct iphdr); - if (sk && !sk->ip_hdrincl && opt) + if (!sk->ip_hdrincl) + length -= sizeof(struct iphdr); + + if(opt) { length -= opt->optlen; fragheaderlen = dev->hard_header_len + sizeof(struct iphdr) + opt->optlen; @@ -810,6 +812,7 @@ skb->sk = sk; skb->arp = 0; skb->saddr = saddr; + skb->daddr = daddr; skb->raddr = raddr; skb_reserve(skb,(dev->hard_header_len+15)&~15); data = skb_put(skb, fraglen-dev->hard_header_len); @@ -839,6 +842,8 @@ NULL, NULL, 0)>0) skb->arp=1; } + else + skb->arp = 1; /* * Find where to start putting bytes. @@ -927,7 +932,7 @@ if(sk==NULL || sk->ip_mc_loop) { - if(skb->daddr==IGMP_ALL_HOSTS || (dev->flags&IFF_ALLMULTI)) + if(daddr==IGMP_ALL_HOSTS || (dev->flags&IFF_ALLMULTI)) ip_loopback(dev,skb); else { @@ -950,7 +955,11 @@ */ if(skb->ip_hdr->ttl==0) - kfree_skb(skb, FREE_READ); + { + kfree_skb(skb, FREE_WRITE); + nfrags++; + continue; + } } #endif diff -ur --new-file old/linux/net/ipv4/ip_sockglue.c new/linux/net/ipv4/ip_sockglue.c --- old/linux/net/ipv4/ip_sockglue.c Tue May 7 11:06:53 1996 +++ new/linux/net/ipv4/ip_sockglue.c Thu Jul 11 07:54:18 1996 @@ -178,17 +178,18 @@ kfree_s(old_opt, sizeof(struct optlen) + old_opt->optlen); return 0; } - case IP_TOS: /* This sets both TOS and Precedence */ - if (val<0 || val>63) /* Reject setting of unused bits */ + case IP_TOS: /* This sets both TOS and Precedence */ + if (val & ~0xfe) /* Reject setting of unused bits */ return -EINVAL; - if ((val&7) > 4 && !suser()) /* Only root can set Prec>4 */ + if ((val>>5) > 4 && !suser()) /* Only root can set Prec>4 */ return -EPERM; sk->ip_tos=val; - switch (val & 0x38) { + switch (val & 0x1E) { case IPTOS_LOWDELAY: sk->priority=SOPRI_INTERACTIVE; break; case IPTOS_THROUGHPUT: + case IPTOS_MINCOST: sk->priority=SOPRI_BACKGROUND; break; default: @@ -270,7 +271,6 @@ * FIXME: Add/Del membership should have a semaphore protecting them from re-entry */ struct ip_mreq mreq; - __u32 route_src; struct rtable *rt; struct device *dev=NULL; @@ -296,7 +296,6 @@ if((rt=ip_rt_route(mreq.imr_multiaddr.s_addr,0))!=NULL) { dev=rt->rt_dev; - route_src = rt->rt_src; atomic_dec(&rt->rt_use); ip_rt_put(rt); } @@ -328,7 +327,6 @@ { struct ip_mreq mreq; struct rtable *rt; - __u32 route_src; struct device *dev=NULL; /* @@ -351,7 +349,6 @@ { dev=rt->rt_dev; atomic_dec(&rt->rt_use); - route_src = rt->rt_src; ip_rt_put(rt); } } diff -ur --new-file old/linux/net/ipv4/ipmr.c new/linux/net/ipv4/ipmr.c --- old/linux/net/ipv4/ipmr.c Fri May 31 12:46:27 1996 +++ new/linux/net/ipv4/ipmr.c Fri Jul 19 07:24:05 1996 @@ -1,5 +1,5 @@ /* - * IP multicast routing support for mrouted 3.6 + * IP multicast routing support for mrouted 3.6/3.8 * * (c) 1995 Alan Cox, * Linux Consultancy and Custom Driver Development @@ -12,8 +12,11 @@ * * Fixes: * Michael Chastain : Incorrect size of copying. - * Alan Cox : Added the cache manager code + * Alan Cox : Added the cache manager code. * Alan Cox : Fixed the clone/copy bug and device race. + * Malcolm Beattie : Buffer handling fixes. + * Alexey Kuznetsov : Double buffer free and other fixes. + * SVR Anand : Fixed several multicast bugs and problems. * * Status: * Cache manager under test. Forwarding in vague test mode @@ -736,7 +739,14 @@ kfree_skb(skb, FREE_WRITE); return; } + + /* + * Without the following addition, skb->h.iph points to something + * different that is not the ip header. + */ + skb->h.iph = skb->ip_hdr; /* Anand, ernet. */ + vif_table[vif].pkt_in++; vif_table[vif].bytes_in+=skb->len; @@ -909,7 +919,7 @@ void ip_mr_init(void) { - printk(KERN_INFO "Linux IP multicast router 0.05.\n"); + printk(KERN_INFO "Linux IP multicast router 0.06.\n"); register_netdevice_notifier(&ip_mr_notifier); #ifdef CONFIG_PROC_FS proc_net_register(&(struct proc_dir_entry) { diff -ur --new-file old/linux/net/ipv4/rarp.c new/linux/net/ipv4/rarp.c --- old/linux/net/ipv4/rarp.c Mon May 13 11:15:24 1996 +++ new/linux/net/ipv4/rarp.c Thu Aug 1 14:43:04 1996 @@ -150,7 +150,6 @@ if (entry->dev == dev) { *pentry = entry->next; - sti(); rarp_release_entry(entry); } else diff -ur --new-file old/linux/net/ipv4/tcp.c new/linux/net/ipv4/tcp.c --- old/linux/net/ipv4/tcp.c Thu Aug 29 16:32:45 1996 +++ new/linux/net/ipv4/tcp.c Thu Aug 29 16:33:32 1996 @@ -202,6 +202,7 @@ * improvement. * Stefan Magdalinski : adjusted tcp_readable() to fix FIONREAD * Willy Konynenberg : Transparent proxying support. + * Theodore Ts'o : Do secure TCP sequence numbers. * * To Fix: * Fast path the code. Two things here - fix the window calculation @@ -427,6 +428,7 @@ #include #include #include +#include #include #include @@ -551,8 +553,15 @@ if (rt->rt_mtu > new_mtu) rt->rt_mtu = new_mtu; + /* + * FIXME:: + * Not the nicest of fixes: Lose a MTU update if the socket is + * locked this instant. Not the right answer but will be best + * for the production fix. Make 2.1 work right! + */ + if (sk->mtu > new_mtu - sizeof(struct iphdr) - sizeof(struct tcphdr) - && new_mtu > sizeof(struct iphdr)+sizeof(struct tcphdr)) + && new_mtu > sizeof(struct iphdr)+sizeof(struct tcphdr) && !sk->users) sk->mtu = new_mtu - sizeof(struct iphdr) - sizeof(struct tcphdr); return; @@ -717,12 +726,7 @@ return 0; if (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV) break; - /* - * This is now right thanks to a small fix - * by Matt Dillon. - */ - - if (sock_wspace(sk) < sk->mtu+128+sk->prot->max_header) + if (sk->wmem_alloc*2 > sk->sndbuf) break; return 1; @@ -852,6 +856,11 @@ lock_sock(sk); } +static inline int tcp_memory_free(struct sock *sk) +{ + return sk->wmem_alloc < sk->sndbuf; +} + /* * Wait for more memory for a socket */ @@ -859,9 +868,9 @@ { release_sock(sk); cli(); - if (sk->wmem_alloc*2 > sk->sndbuf && + if (!tcp_memory_free(sk) && (sk->state == TCP_ESTABLISHED||sk->state == TCP_CLOSE_WAIT) - && sk->err == 0) + && sk->err == 0 /* && check shutdown ?? */) { sk->socket->flags &= ~SO_NOSPACE; interruptible_sleep_on(sk->sleep); @@ -943,40 +952,48 @@ return -EPIPE; } - /* - * The following code can result in copy <= if sk->mss is ever - * decreased. It shouldn't be. sk->mss is min(sk->mtu, sk->max_window). - * sk->mtu is constant once SYN processing is finished. I.e. we - * had better not get here until we've seen his SYN and at least one - * valid ack. (The SYN sets sk->mtu and the ack sets sk->max_window.) - * But ESTABLISHED should guarantee that. sk->max_window is by definition - * non-decreasing. Note that any ioctl to set user_mss must be done - * before the exchange of SYN's. If the initial ack from the other - * end has a window of 0, max_window and thus mss will both be 0. - */ + /* + * The following code can result in copy <= if sk->mss is ever + * decreased. It shouldn't be. sk->mss is min(sk->mtu, sk->max_window). + * sk->mtu is constant once SYN processing is finished. I.e. we + * had better not get here until we've seen his SYN and at least one + * valid ack. (The SYN sets sk->mtu and the ack sets sk->max_window.) + * But ESTABLISHED should guarantee that. sk->max_window is by definition + * non-decreasing. Note that any ioctl to set user_mss must be done + * before the exchange of SYN's. If the initial ack from the other + * end has a window of 0, max_window and thus mss will both be 0. + */ - /* - * Now we need to check if we have a half built packet. - */ + /* + * Now we need to check if we have a half built packet. + */ #ifndef CONFIG_NO_PATH_MTU_DISCOVERY - /* - * FIXME: I'm almost sure that this fragment is BUG, - * but it works... I do not know why 8) --ANK - * - * Really, we should rebuild all the queues... - * It's difficult. Temporary hack is to send all - * queued segments with allowed fragmentation. - */ - { - int new_mss = min(sk->mtu, sk->max_window); - if (new_mss < sk->mss) + /* + * Really, we should rebuild all the queues... + * It's difficult. Temporary hack is to send all + * queued segments with allowed fragmentation. + */ { - tcp_send_partial(sk); - sk->mss = new_mss; + /* + * new_mss may be zero. That indicates + * we don't have a window estimate for + * the remote box yet. + * -- AC + */ + + int new_mss = min(sk->mtu, sk->max_window); + if (new_mss && new_mss < sk->mss) + { + tcp_send_partial(sk); + sk->mss = new_mss; + } } - } #endif + /* + * If there is a partly filled frame we can fill + * out. + */ if ((skb = tcp_dequeue_partial(sk)) != NULL) { int tcp_size; @@ -987,11 +1004,33 @@ if (!(flags & MSG_OOB)) { copy = min(sk->mss - tcp_size, seglen); + + /* + * Now we may find the frame is as big, or too + * big for our MSS. Thats all fine. It means the + * MSS shrank (from an ICMP) after we allocated + * this frame. + */ + if (copy <= 0) { - printk(KERN_CRIT "TCP: **bug**: \"copy\" <= 0\n"); - return -EFAULT; + /* + * Send the now forced complete frame out. + * + * Note for 2.1: The MSS reduce code ought to + * flush any frames in partial that are now + * full sized. Not serious, potential tiny + * performance hit. + */ + tcp_send_skb(sk,skb); + /* + * Get a new buffer and try again. + */ + continue; } + /* + * Otherwise continue to fill the buffer. + */ tcp_size += copy; memcpy_fromfs(skb_put(skb,copy), from, copy); skb->csum = csum_partial(skb->tail - tcp_size, tcp_size, 0); @@ -1378,11 +1417,9 @@ current->state = TASK_INTERRUPTIBLE; - skb = skb_peek(&sk->receive_queue); - do + skb = sk->receive_queue.next; + while (skb != (struct sk_buff *)&sk->receive_queue) { - if (!skb) - break; if (before(*seq, skb->seq)) break; offset = *seq - skb->seq; @@ -1396,12 +1433,11 @@ skb->used = 1; skb = skb->next; } - while (skb != (struct sk_buff *)&sk->receive_queue); if (copied) break; - if (sk->err) + if (sk->err && !(flags&MSG_PEEK)) { copied = sock_error(sk); break; @@ -1856,6 +1892,36 @@ goto out; } +/* + * Check that a TCP address is unique, don't allow multiple + * connects to/from the same address + */ +static int tcp_unique_address(u32 saddr, u16 snum, u32 daddr, u16 dnum) +{ + int retval = 1; + struct sock * sk; + + /* Make sure we are allowed to connect here. */ + cli(); + for (sk = tcp_prot.sock_array[snum & (SOCK_ARRAY_SIZE -1)]; + sk != NULL; sk = sk->next) + { + /* hash collision? */ + if (sk->num != snum) + continue; + if (sk->saddr != saddr) + continue; + if (sk->daddr != daddr) + continue; + if (sk->dummy_th.dest != dnum) + continue; + retval = 0; + break; + } + sti(); + return retval; +} + /* * This will initiate an outgoing connection. @@ -1891,7 +1957,7 @@ * connect() to INADDR_ANY means loopback (BSD'ism). */ - if(usin->sin_addr.s_addr==INADDR_ANY) + if (usin->sin_addr.s_addr==INADDR_ANY) usin->sin_addr.s_addr=ip_my_addr(); /* @@ -1901,27 +1967,26 @@ if ((atype=ip_chk_addr(usin->sin_addr.s_addr)) == IS_BROADCAST || atype==IS_MULTICAST) return -ENETUNREACH; + if (!tcp_unique_address(sk->saddr, sk->num, usin->sin_addr.s_addr, usin->sin_port)) + return -EADDRNOTAVAIL; + lock_sock(sk); sk->daddr = usin->sin_addr.s_addr; - sk->write_seq = tcp_init_seq(); - sk->window_seq = sk->write_seq; - sk->rcv_ack_seq = sk->write_seq -1; + sk->rcv_ack_cnt = 1; sk->err = 0; sk->dummy_th.dest = usin->sin_port; - release_sock(sk); buff = sock_wmalloc(sk,MAX_SYN_SIZE,0, GFP_KERNEL); if (buff == NULL) { + release_sock(sk); return(-ENOMEM); } - lock_sock(sk); buff->sk = sk; buff->free = 0; buff->localroute = sk->localroute; - /* * Put in the IP header and routing stuff. */ @@ -1942,6 +2007,15 @@ if ((rt = sk->ip_route_cache) != NULL && !sk->saddr) sk->saddr = rt->rt_src; sk->rcv_saddr = sk->saddr; + + /* + * Set up our outgoing TCP sequence number + */ + sk->write_seq = secure_tcp_sequence_number(sk->saddr, sk->daddr, + sk->dummy_th.source, + usin->sin_port); + sk->window_seq = sk->write_seq; + sk->rcv_ack_seq = sk->write_seq -1; t1 = (struct tcphdr *) skb_put(buff,sizeof(struct tcphdr)); diff -ur --new-file old/linux/net/ipv4/tcp_input.c new/linux/net/ipv4/tcp_input.c --- old/linux/net/ipv4/tcp_input.c Thu Aug 29 16:32:46 1996 +++ new/linux/net/ipv4/tcp_input.c Thu Aug 29 16:33:33 1996 @@ -28,9 +28,12 @@ * Eric Schenk : Skip fast retransmit on small windows. * Eric schenk : Fixes to retransmission code to * : avoid extra retransmission. + * Theodore Ts'o : Do secure TCP sequence numbers. */ #include +#include +#include #include #ifdef CONFIG_AREQUIPA @@ -71,7 +74,7 @@ /* This used to test against sk->rtt. * On a purely receiving link, there is no rtt measure. - * The result is that we loose delayed ACKs on one way links. + * The result is that we lose delayed ACKs on one-way links. * Therefore we test against sk->rto, which will always * at least have a default value. */ @@ -213,7 +216,17 @@ * from the far end, but sometimes it means the far end lost * an ACK we sent, so we better send an ACK. */ - tcp_send_ack(sk); + /* + * BEWARE! Unconditional answering by ack to out-of-window ack + * can result in infinite exchange of empty acks. + * This check cures bug, found by Michiel Boland, but + * not another possible cases. + * If we are in TCP_TIME_WAIT, we have already received + * FIN, so that our peer need not window update. If our + * ACK were lost, peer would retransmit his FIN anyway. --ANK + */ + if (sk->state != TCP_TIME_WAIT || ntohl(th->seq) != end_seq) + tcp_send_ack(sk); } /* @@ -883,11 +896,11 @@ * sensitive to minor changes in the round trip time. * We add in two compensating factors. * First we multiply by 5/4. For large congestion - * windows this allows us to tollerate burst traffic + * windows this allows us to tolerate burst traffic * delaying up to 1/4 of our packets. * We also add in a rtt / cong_window term. * For small congestion windows this allows - * a single packet delay, but has neglibible effect + * a single packet delay, but has negligible effect * on the compensation for large windows. */ sk->rto = (sk->rtt >> 3) + sk->mdev; @@ -1305,7 +1318,7 @@ * and lost it from the queue before * changing the ack properly]. */ - printk(KERN_ERR "Lost timer or fin packet in tcp_fin."); + printk(KERN_ERR "Lost timer or fin packet in tcp_fin.\n"); } } tcp_set_state(sk,TCP_CLOSING); @@ -1745,6 +1758,7 @@ struct tcphdr *th; struct sock *sk; int syn_ok=0; + __u32 seq; #ifdef CONFIG_IP_TRANSPARENT_PROXY int r; #endif @@ -1878,7 +1892,7 @@ * handle them locally, due to transparent proxying. * Thus, narrow down the test to what is really meant. */ - if(th->rst || !th->syn || th->ack || (r = ip_chk_addr(daddr) == IS_BROADCAST || r == IS_MULTICAST)) + if(th->rst || !th->syn || th->ack || (r = ip_chk_addr(daddr)) == IS_BROADCAST || r == IS_MULTICAST) #else if(th->rst || !th->syn || th->ack || ip_chk_addr(daddr)!=IS_MYADDR) #endif @@ -1888,10 +1902,12 @@ } /* - * Guess we need to make a new socket up + * Guess we need to make a new socket up */ - - tcp_conn_request(sk, skb, daddr, saddr, opt, dev, tcp_init_seq()); + seq = secure_tcp_sequence_number(saddr, daddr, + skb->h.th->dest, + skb->h.th->source); + tcp_conn_request(sk, skb, daddr, saddr, opt, dev, seq); /* * Now we have several options: In theory there is nothing else @@ -1931,7 +1947,7 @@ { /* We got an ack, but it's not a good ack. * We used to test this with a call to tcp_ack, - * but this looses, because it takes the SYN + * but this loses, because it takes the SYN * packet out of the send queue, even if * the ACK doesn't have the SYN bit sent, and * therefore isn't the one we are waiting for. @@ -1961,7 +1977,7 @@ /* process the ACK, get the SYN packet out * of the send queue, do other initial - * processing stuff. [We know its good, and + * processing stuff. [We know it's good, and * we know it's the SYN,ACK we want.] */ tcp_ack(sk,th,skb->ack_seq,len); diff -ur --new-file old/linux/net/ipv4/tcp_output.c new/linux/net/ipv4/tcp_output.c --- old/linux/net/ipv4/tcp_output.c Sat Jun 8 15:22:56 1996 +++ new/linux/net/ipv4/tcp_output.c Wed Aug 7 08:37:34 1996 @@ -279,7 +279,7 @@ /* * Wait up to 1 second for the buffer to fill. */ - sk->partial_timer.expires = jiffies+HZ; + sk->partial_timer.expires = jiffies+HZ/10; sk->partial_timer.function = (void (*)(unsigned long)) tcp_send_partial; sk->partial_timer.data = (unsigned long) sk; add_timer(&sk->partial_timer); @@ -623,7 +623,7 @@ * and then put it into the queue to be sent. */ - buff = sock_wmalloc(NULL, MAX_RESET_SIZE, 1, GFP_ATOMIC); + buff = alloc_skb(MAX_RESET_SIZE, GFP_ATOMIC); if (buff == NULL) return; @@ -878,17 +878,12 @@ */ void tcp_send_delayed_ack(struct sock * sk, int max_timeout, unsigned long timeout) { - unsigned long now; - /* Calculate new timeout */ - now = jiffies; if (timeout > max_timeout) timeout = max_timeout; - timeout += now; - if (sk->bytes_rcv >= sk->max_unacked) { - timeout = now; - mark_bh(TIMER_BH); - } + if (sk->bytes_rcv >= sk->max_unacked) + timeout = 0; + timeout += jiffies; /* Use new timeout only if there wasn't a older one earlier */ if (!del_timer(&sk->delack_timer) || timeout < sk->delack_timer.expires) @@ -971,6 +966,10 @@ sock_wfree(sk, buff); return; } +#ifndef CONFIG_NO_PATH_MTU_DISCOVERY + buff->ip_hdr->frag_off |= htons(IP_DF); +#endif + t1 =(struct tcphdr *)skb_put(buff,sizeof(struct tcphdr)); /* diff -ur --new-file old/linux/net/ipx/af_ipx.c new/linux/net/ipx/af_ipx.c --- old/linux/net/ipx/af_ipx.c Fri May 31 12:46:27 1996 +++ new/linux/net/ipx/af_ipx.c Fri Jul 19 07:24:05 1996 @@ -1267,7 +1267,7 @@ * Route an outgoing frame from a socket. */ -static int ipxrtr_route_packet(ipx_socket *sk, struct sockaddr_ipx *usipx, struct iovec *iov, int len) +static int ipxrtr_route_packet(ipx_socket *sk, struct sockaddr_ipx *usipx, struct iovec *iov, int len, int noblock) { struct sk_buff *skb; ipx_interface *intrfc; @@ -1296,7 +1296,7 @@ size=sizeof(ipx_packet)+len; size += ipx_offset; - skb=sock_alloc_send_skb(sk, size, 0, 0, &err); + skb=sock_alloc_send_skb(sk, size, 0, noblock, &err); if(skb==NULL) return err; @@ -2133,7 +2133,7 @@ memcpy(usipx->sipx_node,sk->protinfo.af_ipx.dest_addr.node,IPX_NODE_LEN); } - retval = ipxrtr_route_packet(sk, usipx, msg->msg_iov, len); + retval = ipxrtr_route_packet(sk, usipx, msg->msg_iov, len, noblock); if (retval < 0) return retval; diff -ur --new-file old/linux/net/netrom/af_netrom.c new/linux/net/netrom/af_netrom.c --- old/linux/net/netrom/af_netrom.c Fri May 31 12:46:27 1996 +++ new/linux/net/netrom/af_netrom.c Wed Aug 7 07:41:57 1996 @@ -934,7 +934,7 @@ sax->fsa_ax25.sax25_ndigis = 1; sax->fsa_ax25.sax25_call = sk->nr->user_addr; sax->fsa_digipeater[0] = sk->nr->dest_addr; - *uaddr_len = sizeof(struct sockaddr_ax25) + AX25_ADDR_LEN; + *uaddr_len = sizeof(struct full_sockaddr_ax25); } else { sax->fsa_ax25.sax25_family = AF_NETROM; sax->fsa_ax25.sax25_ndigis = 0; @@ -952,14 +952,13 @@ ax25_address *src, *dest, *user; unsigned short circuit_index, circuit_id; unsigned short frametype, window, timeout; - skb->sk = NULL; /* Initially we don't know who it's for */ /* * skb->data points to the netrom frame start */ - + src = (ax25_address *)(skb->data + 0); dest = (ax25_address *)(skb->data + 7); @@ -1327,7 +1326,7 @@ cli(); - len += sprintf(buffer, "user_addr dest_node src_node dev my your st vs vr va t1 t2 n2 rtt wnd paclen Snd-Q Rcv-Q\n"); + len += sprintf(buffer, "user_addr dest_node src_node dev my your st vs vr va t1 t2 n2 rtt wnd paclen Snd-Q Rcv-Q\n"); for (s = nr_list; s != NULL; s = s->next) { if ((dev = s->nr->device) == NULL) @@ -1339,7 +1338,7 @@ ax2asc(&s->nr->user_addr)); len += sprintf(buffer + len, "%-9s ", ax2asc(&s->nr->dest_addr)); - len += sprintf(buffer + len, "%-9s %-3s %02X/%02X %02X/%02X %2d %2d %2d %2d %3d/%03d %2d/%02d %2d/%02d %3d %3d %6d %5d %5d\n", + len += sprintf(buffer + len, "%-9s %-3s %02X/%02X %02X/%02X %2d %3d %3d %3d %3d/%03d %2d/%02d %2d/%02d %3d %3d %6d %5d %5d\n", ax2asc(&s->nr->source_addr), devname, s->nr->my_index, s->nr->my_id, s->nr->your_index, s->nr->your_id, diff -ur --new-file old/linux/net/netrom/nr_out.c new/linux/net/netrom/nr_out.c --- old/linux/net/netrom/nr_out.c Thu Apr 18 13:35:34 1996 +++ new/linux/net/netrom/nr_out.c Wed Aug 7 07:41:57 1996 @@ -168,7 +168,7 @@ do { if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) { skb_queue_head(&sk->write_queue, skb); - return; + break; } next = (sk->nr->vs + 1) % NR_MODULUS; diff -ur --new-file old/linux/net/netrom/nr_route.c new/linux/net/netrom/nr_route.c --- old/linux/net/netrom/nr_route.c Sun May 19 22:40:51 1996 +++ new/linux/net/netrom/nr_route.c Wed Aug 7 07:41:57 1996 @@ -16,13 +16,10 @@ * NET/ROM 001 Jonathan(G4KLX) First attempt. * NET/ROM 003 Jonathan(G4KLX) Use SIOCADDRT/SIOCDELRT ioctl values * for NET/ROM routes. + * Use '*' for a blank mnemonic in /proc/net/nr_nodes. + * Change default quality for new neighbour when same + * as node callsign. * Alan Cox(GW4PTS) Added the firewall hooks. - * - * TO DO - * Sort out the which pointer when shuffling entries in the routes - * section. Also reset the which pointer when a route becomes "good" - * again, ie when a NODES broadcast is processed via calls to - * nr_add_node(). */ #include @@ -54,12 +51,14 @@ #include #include -static int nr_neigh_no = 1; +static unsigned int nr_neigh_no = 1; static int nr_route_on = 1; static struct nr_node *nr_node_list = NULL; static struct nr_neigh *nr_neigh_list = NULL; +static void nr_remove_neigh(struct nr_neigh *); + /* * Add a new route to a node, and in the process add the node and the * neighbour if it is new. @@ -72,7 +71,10 @@ struct nr_route nr_route; unsigned long flags; int i, found; - + + if (nr_dev_get(nr) != NULL) /* Can't add routes to ourself */ + return -EINVAL; + for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next) if (ax25cmp(nr, &nr_node->callsign) == 0) break; @@ -91,7 +93,10 @@ nr_neigh->callsign = *ax25; nr_neigh->digipeat = NULL; nr_neigh->dev = dev; - nr_neigh->quality = nr_default.quality; + if (ax25cmp(nr, ax25) == 0) + nr_neigh->quality = quality; + else + nr_neigh->quality = nr_default.quality; nr_neigh->locked = 0; nr_neigh->count = 0; nr_neigh->number = nr_neigh_no++; @@ -118,14 +123,14 @@ return -ENOMEM; nr_node->callsign = *nr; - memcpy(&nr_node->mnemonic, mnemonic, sizeof(nr_node->mnemonic)); + strcpy(nr_node->mnemonic, mnemonic); nr_node->which = 0; nr_node->count = 1; nr_node->routes[0].quality = quality; nr_node->routes[0].obs_count = obs_count; - nr_node->routes[0].neighbour = nr_neigh->number; + nr_node->routes[0].neighbour = nr_neigh; save_flags(flags); cli(); @@ -138,10 +143,13 @@ nr_neigh->count++; return 0; + } else { + if (nr_node->mnemonic[0] == '\0') + strcpy(nr_node->mnemonic, mnemonic); } for (found = 0, i = 0; i < nr_node->count; i++) { - if (nr_node->routes[i].neighbour == nr_neigh->number) { + if (nr_node->routes[i].neighbour == nr_neigh) { nr_node->routes[i].quality = quality; nr_node->routes[i].obs_count = obs_count; found = 1; @@ -157,16 +165,22 @@ nr_node->routes[0].quality = quality; nr_node->routes[0].obs_count = obs_count; - nr_node->routes[0].neighbour = nr_neigh->number; + nr_node->routes[0].neighbour = nr_neigh; + nr_node->which++; nr_node->count++; nr_neigh->count++; } else { /* It must be better than the worst */ if (quality > nr_node->routes[2].quality) { + nr_node->routes[2].neighbour->count--; + + if (nr_node->routes[2].neighbour->count == 0 && !nr_node->routes[2].neighbour->locked) + nr_remove_neigh(nr_node->routes[2].neighbour); + nr_node->routes[2].quality = quality; nr_node->routes[2].obs_count = obs_count; - nr_node->routes[2].neighbour = nr_neigh->number; + nr_node->routes[2].neighbour = nr_neigh; nr_neigh->count++; } @@ -212,7 +226,7 @@ } for (i = 0; i < nr_node->count; i++) { - if (nr_node->routes[i].neighbour == nr_neigh->number) { + if (nr_node->routes[i].neighbour == nr_neigh) { if (i < nr_node->which) nr_node->which = i; break; @@ -307,7 +321,7 @@ if (nr_neigh == NULL) return -EINVAL; for (i = 0; i < nr_node->count; i++) { - if (nr_node->routes[i].neighbour == nr_neigh->number) { + if (nr_node->routes[i].neighbour == nr_neigh) { nr_neigh->count--; if (nr_neigh->count == 0 && !nr_neigh->locked) @@ -403,7 +417,7 @@ */ static int nr_dec_obs(void) { - struct nr_neigh *t, *nr_neigh; + struct nr_neigh *nr_neigh; struct nr_node *s, *nr_node; int i; @@ -420,21 +434,12 @@ break; case 1: /* From 1 -> 0 */ - nr_neigh = nr_neigh_list; - - while (nr_neigh != NULL) { - t = nr_neigh; - nr_neigh = nr_neigh->next; - - if (t->number == s->routes[i].neighbour) { - t->count--; + nr_neigh = s->routes[i].neighbour; + + nr_neigh->count--; - if (t->count == 0 && !t->locked) - nr_remove_neigh(t); - - break; - } - } + if (nr_neigh->count == 0 && !nr_neigh->locked) + nr_remove_neigh(nr_neigh); s->count--; @@ -483,7 +488,7 @@ nr_node = nr_node->next; for (i = 0; i < t->count; i++) { - if (t->routes[i].neighbour == s->number) { + if (t->routes[i].neighbour == s) { t->count--; switch (i) { @@ -609,13 +614,16 @@ case SIOCNRDECOBS: return nr_dec_obs(); - + case SIOCNRRTCTL: if ((err = verify_area(VERIFY_READ, arg, sizeof(int))) != 0) return err; opt = get_fs_long((void *)arg); nr_route_on = opt ? 1 : 0; return 0; + + default: + return -EINVAL; } return 0; @@ -637,7 +645,7 @@ if (nr_neigh == NULL) return; for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next) - if (nr_node->which >= nr_node->count && nr_node->routes[nr_node->which].neighbour == nr_neigh->number) + if (nr_node->which < nr_node->count && nr_node->routes[nr_node->which].neighbour == nr_neigh) nr_node->which++; } @@ -645,7 +653,6 @@ * Route a frame to an appropriate AX.25 connection. A NULL ax25_cb * indicates an internally generated frame. */ - int nr_route_frame(struct sk_buff *skb, ax25_cb *ax25) { ax25_address *nr_src, *nr_dest; @@ -655,12 +662,12 @@ unsigned char *dptr; #ifdef CONFIG_FIREWALL - - if(ax25 && call_in_firewall(PF_NETROM, skb->dev, skb->data, NULL)!=FW_ACCEPT) + if (ax25 != NULL && call_in_firewall(PF_NETROM, skb->dev, skb->data, NULL) != FW_ACCEPT) return 0; - if(!ax25 && call_out_firewall(PF_NETROM, skb->dev, skb->data, NULL)!=FW_ACCEPT) + if (ax25 == NULL && call_out_firewall(PF_NETROM, skb->dev, skb->data, NULL) != FW_ACCEPT) return 0; #endif + nr_src = (ax25_address *)(skb->data + 0); nr_dest = (ax25_address *)(skb->data + 7); @@ -684,27 +691,20 @@ if (nr_node == NULL || nr_node->which >= nr_node->count) return 0; - for (nr_neigh = nr_neigh_list; nr_neigh != NULL; nr_neigh = nr_neigh->next) - if (nr_neigh->number == nr_node->routes[nr_node->which].neighbour) - break; - - if (nr_neigh == NULL) - return 0; + nr_neigh = nr_node->routes[nr_node->which].neighbour; if ((dev = nr_dev_first()) == NULL) return 0; #ifdef CONFIG_FIREWALL - if(ax25 && call_fw_firewall(PF_NETROM, skb->dev, skb->data, NULL)!=FW_ACCEPT) + if (ax25 != NULL && call_fw_firewall(PF_NETROM, skb->dev, skb->data, NULL) != FW_ACCEPT) return 0; #endif dptr = skb_push(skb, 1); *dptr = AX25_P_NETROM; - ax25_send_frame(skb, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev); - - return 1; + return ax25_send_frame(skb, (ax25_address *)dev->dev_addr, &nr_neigh->callsign, nr_neigh->digipeat, nr_neigh->dev); } int nr_nodes_get_info(char *buffer, char **start, off_t offset, @@ -715,7 +715,7 @@ off_t pos = 0; off_t begin = 0; int i; - + cli(); len += sprintf(buffer, "callsign mnemonic w n qual obs neigh qual obs neigh qual obs neigh\n"); @@ -723,7 +723,7 @@ for (nr_node = nr_node_list; nr_node != NULL; nr_node = nr_node->next) { len += sprintf(buffer + len, "%-9s %-7s %d %d", ax2asc(&nr_node->callsign), - nr_node->mnemonic, + (nr_node->mnemonic[0] == '\0') ? "*" : nr_node->mnemonic, nr_node->which + 1, nr_node->count); @@ -731,7 +731,7 @@ len += sprintf(buffer + len, " %3d %d %05d", nr_node->routes[i].quality, nr_node->routes[i].obs_count, - nr_node->routes[i].neighbour); + nr_node->routes[i].neighbour->number); } len += sprintf(buffer + len, "\n"); @@ -742,7 +742,7 @@ len = 0; begin = pos; } - + if (pos > offset + length) break; } @@ -754,7 +754,7 @@ if (len > length) len = length; - return(len); + return len; } int nr_neigh_get_info(char *buffer, char **start, off_t offset, @@ -764,7 +764,7 @@ int len = 0; off_t pos = 0; off_t begin = 0; - + cli(); len += sprintf(buffer, "addr callsign dev qual lock count\n"); @@ -796,7 +796,7 @@ if (len > length) len = length; - return(len); + return len; } #endif diff -ur --new-file old/linux/net/netsyms.c new/linux/net/netsyms.c --- old/linux/net/netsyms.c Wed Jun 5 13:42:27 1996 +++ new/linux/net/netsyms.c Fri Jul 19 07:24:05 1996 @@ -159,6 +159,7 @@ X(skb_clone), X(dev_alloc_skb), X(dev_kfree_skb), + X(skb_device_unlock), X(netif_rx), X(dev_tint), X(irq2dev_map), diff -ur --new-file old/linux/net/socket.c new/linux/net/socket.c --- old/linux/net/socket.c Thu Aug 29 16:32:46 1996 +++ new/linux/net/socket.c Mon Jul 15 10:31:51 1996 @@ -172,36 +172,31 @@ static int get_fd(struct inode *inode) { int fd; - struct file *file; /* * Find a file descriptor suitable for return to the user. */ - file = get_empty_filp(); - if (!file) - return(-1); - - for (fd = 0; fd < NR_OPEN; ++fd) - if (!current->files->fd[fd]) - break; - if (fd == NR_OPEN) - { - file->f_count = 0; - return(-1); - } + fd = get_unused_fd(); + if (fd >= 0) { + struct file *file = get_empty_filp(); + + if (!file) { + put_unused_fd(fd); + return -ENFILE; + } - FD_CLR(fd, ¤t->files->close_on_exec); current->files->fd[fd] = file; - file->f_op = &socket_file_ops; - file->f_mode = 3; - file->f_flags = O_RDWR; - file->f_count = 1; - file->f_inode = inode; - if (inode) - inode->i_count++; - file->f_pos = 0; - return(fd); + file->f_op = &socket_file_ops; + file->f_mode = 3; + file->f_flags = O_RDWR; + file->f_count = 1; + file->f_inode = inode; + if (inode) + inode->i_count++; + file->f_pos = 0; + } + return fd; } @@ -949,17 +944,22 @@ err=verify_area(VERIFY_READ,buff,len); if(err) return err; - - if((err=move_addr_to_kernel(addr,addr_len,address))<0) - return err; - + iov.iov_base=buff; iov.iov_len=len; - msg.msg_name=address; - msg.msg_namelen=addr_len; + msg.msg_name = NULL; + msg.msg_namelen = 0; msg.msg_iov=&iov; msg.msg_iovlen=1; msg.msg_control=NULL; + if (addr && addr_len) { + err=move_addr_to_kernel(addr,addr_len,address); + if (err < 0) + return err; + msg.msg_name=address; + msg.msg_namelen=addr_len; + } + return(sock->ops->sendmsg(sock, &msg, len, (file->f_flags & O_NONBLOCK), flags)); } diff -ur --new-file old/linux/net/unix/af_unix.c new/linux/net/unix/af_unix.c --- old/linux/net/unix/af_unix.c Thu May 16 15:35:56 1996 +++ new/linux/net/unix/af_unix.c Fri Jul 5 15:57:33 1996 @@ -710,10 +710,9 @@ int num=cmsg->cmsg_len-sizeof(struct cmsghdr); int i; int *fdp=(int *)cmsg->cmsg_data; - num/=4; /* Odd bytes are forgotten in BSD not errored */ - - if(num>=UNIX_MAX_FD) + num /= sizeof(int); /* Odd bytes are forgotten in BSD not errored */ + if (num >= UNIX_MAX_FD) return -EINVAL; /* @@ -728,9 +727,9 @@ #if 0 printk("testing fd %d\n", fd); #endif - if(fd < 0|| fd >=NR_OPEN) + if (fd < 0 || fd >= NR_OPEN) return -EBADF; - if(current->files->fd[fd]==NULL) + if (current->files->fd[fd]==NULL) return -EBADF; } @@ -759,30 +758,6 @@ } } -/* - * Count the free descriptors available to a process. - * Interpretation issue: Is the limit the highest descriptor (buggy - * allowing passed fd's higher up to cause a limit to be exceeded) - - * but how the old code did it - or like this... - */ - -static int unix_files_free(void) -{ - int i; - int n=0; - for (i=0;ifiles->fd[i]) - n++; - } - - i=NR_OPEN; - if(i>current->rlim[RLIMIT_NOFILE].rlim_cur) - i=current->rlim[RLIMIT_NOFILE].rlim_cur; - if(n>=i) - return 0; - return i-n; -} /* * Perform the AF_UNIX file descriptor pass out functionality. This @@ -795,50 +770,39 @@ /* count of space in parent for fds */ int cmnum; struct file **fp; - struct file **ufp; - int *cmfptr=NULL; /* =NULL To keep gcc happy */ - /* number of fds actually passed */ + int *cmfptr; int fdnum; - int ffree; - int ufn=0; - if(cmsg==NULL) - cmnum=0; - else - { - cmnum=cmsg->cmsg_len-sizeof(struct cmsghdr); - cmnum/=sizeof(int); - cmfptr=(int *)&cmsg->cmsg_data; + cmfptr = NULL; + cmnum = 0; + if (cmsg) + { + cmnum = (cmsg->cmsg_len-sizeof(struct cmsghdr)) / sizeof(int); + cmfptr = (int *)&cmsg->cmsg_data; } - memcpy(&fdnum,skb->h.filp,sizeof(int)); - fp=(struct file **)(skb->h.filp+sizeof(int)); - if(cmnum>fdnum) - cmnum=fdnum; - ffree=unix_files_free(); - if(cmnum>ffree) - cmnum=ffree; - ufp=¤t->files->fd[0]; - + fdnum = *(int *)skb->h.filp; + fp = (struct file **)(skb->h.filp+sizeof(long)); + + if (cmnum > fdnum) + cmnum = fdnum; + /* * Copy those that fit */ - for(i=0;ifiles->close_on_exec); + int new_fd = get_unused_fd(); + if (new_fd < 0) + break; + current->files->fd[new_fd]=fp[i]; + *cmfptr++ = new_fd; unix_notinflight(fp[i]); } /* * Dump those that don't */ - for(;ih.filp=kmalloc(sizeof(int)+fpnum*sizeof(struct file *), + skb->h.filp = kmalloc(sizeof(long)+fpnum*sizeof(struct file *), GFP_KERNEL); /* number of descriptors starts block */ - memcpy(skb->h.filp,&fpnum,sizeof(int)); + *(int *)skb->h.filp = fpnum; /* actual descriptors */ - memcpy(skb->h.filp+sizeof(int),fp,fpnum*sizeof(struct file *)); + memcpy(skb->h.filp+sizeof(long),fp,fpnum*sizeof(struct file *)); skb->destructor = unix_destruct_fds; } diff -ur --new-file old/linux/scripts/Menuconfig new/linux/scripts/Menuconfig --- old/linux/scripts/Menuconfig Tue Jun 4 05:01:25 1996 +++ new/linux/scripts/Menuconfig Wed Jul 10 06:48:35 1996 @@ -733,7 +733,7 @@ # Create a menu item to load an alternate configuration file. # g_alt_config () { - echo -n "get_alt_config 'Load an Alternate Configuration File' "\ + echo -n "get_alt_config 'Load an Alternate Configuration File' "\ >>MCmenu } @@ -742,6 +742,8 @@ # configuration from it. # get_alt_config () { + set -f ## Switch file expansion OFF + while true do ALT_CONFIG="${ALT_CONFIG:-$DEFAULTS}" @@ -759,9 +761,9 @@ [ "_" = "_$ALT_CONFIG" ] && break - if [ -r "$ALT_CONFIG" ] + if eval [ -r "$ALT_CONFIG" ] then - load_config_file "$ALT_CONFIG" + eval load_config_file "$ALT_CONFIG" break else echo -ne "\007" @@ -789,6 +791,7 @@ fi done + set +f ## Switch file expansion ON rm -f help.out MCdialog.out } @@ -796,7 +799,7 @@ # Create a menu item to store an alternate config file. # s_alt_config () { - echo -n "save_alt_config 'Store an Alternate Configuration File' "\ + echo -n "save_alt_config 'Save Configuration to an Alternate File' "\ >>MCmenu } @@ -805,6 +808,8 @@ # configuration to it. # save_alt_config () { + set -f ## Switch file expansion OFF + while true do $DIALOG --backtitle "$backtitle" \ @@ -818,10 +823,10 @@ ALT_CONFIG=`cat MCdialog.out` [ "_" = "_$ALT_CONFIG" ] && break - - if touch $ALT_CONFIG 2>/dev/null + + if eval touch $ALT_CONFIG 2>/dev/null then - save_configuration $ALT_CONFIG + eval save_configuration $ALT_CONFIG load_functions ## RELOAD break else @@ -844,11 +849,12 @@ leave this blank. EOM $DIALOG --backtitle "$backtitle"\ - --title "Store Alternate Configuration"\ + --title "Save Alternate Configuration"\ --textbox help.out $ROWS $COLS fi done + set +f ## Switch file expansion ON rm -f help.out MCdialog.out } .